Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / arm64 / code-generator-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/code-generator.h"
6
7 #include "src/arm64/macro-assembler-arm64.h"
8 #include "src/compiler/code-generator-impl.h"
9 #include "src/compiler/gap-resolver.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/node-properties-inl.h"
12 #include "src/scopes.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 #define __ masm()->
19
20
21 // Adds Arm64-specific methods to convert InstructionOperands.
22 class Arm64OperandConverter FINAL : public InstructionOperandConverter {
23  public:
24   Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
25       : InstructionOperandConverter(gen, instr) {}
26
27   Register InputRegister32(int index) {
28     return ToRegister(instr_->InputAt(index)).W();
29   }
30
31   Register InputRegister64(int index) { return InputRegister(index); }
32
33   Operand InputImmediate(int index) {
34     return ToImmediate(instr_->InputAt(index));
35   }
36
37   Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
38
39   Operand InputOperand64(int index) { return InputOperand(index); }
40
41   Operand InputOperand32(int index) {
42     return ToOperand32(instr_->InputAt(index));
43   }
44
45   Register OutputRegister64() { return OutputRegister(); }
46
47   Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
48
49   Operand InputOperand2_32(int index) {
50     switch (AddressingModeField::decode(instr_->opcode())) {
51       case kMode_None:
52         return InputOperand32(index);
53       case kMode_Operand2_R_LSL_I:
54         return Operand(InputRegister32(index), LSL, InputInt5(index + 1));
55       case kMode_Operand2_R_LSR_I:
56         return Operand(InputRegister32(index), LSR, InputInt5(index + 1));
57       case kMode_Operand2_R_ASR_I:
58         return Operand(InputRegister32(index), ASR, InputInt5(index + 1));
59       case kMode_Operand2_R_ROR_I:
60         return Operand(InputRegister32(index), ROR, InputInt5(index + 1));
61       case kMode_MRI:
62       case kMode_MRR:
63         break;
64     }
65     UNREACHABLE();
66     return Operand(-1);
67   }
68
69   Operand InputOperand2_64(int index) {
70     switch (AddressingModeField::decode(instr_->opcode())) {
71       case kMode_None:
72         return InputOperand64(index);
73       case kMode_Operand2_R_LSL_I:
74         return Operand(InputRegister64(index), LSL, InputInt6(index + 1));
75       case kMode_Operand2_R_LSR_I:
76         return Operand(InputRegister64(index), LSR, InputInt6(index + 1));
77       case kMode_Operand2_R_ASR_I:
78         return Operand(InputRegister64(index), ASR, InputInt6(index + 1));
79       case kMode_Operand2_R_ROR_I:
80         return Operand(InputRegister64(index), ROR, InputInt6(index + 1));
81       case kMode_MRI:
82       case kMode_MRR:
83         break;
84     }
85     UNREACHABLE();
86     return Operand(-1);
87   }
88
89   MemOperand MemoryOperand(int* first_index) {
90     const int index = *first_index;
91     switch (AddressingModeField::decode(instr_->opcode())) {
92       case kMode_None:
93       case kMode_Operand2_R_LSL_I:
94       case kMode_Operand2_R_LSR_I:
95       case kMode_Operand2_R_ASR_I:
96       case kMode_Operand2_R_ROR_I:
97         break;
98       case kMode_MRI:
99         *first_index += 2;
100         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
101       case kMode_MRR:
102         *first_index += 2;
103         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
104                           SXTW);
105     }
106     UNREACHABLE();
107     return MemOperand(no_reg);
108   }
109
110   MemOperand MemoryOperand() {
111     int index = 0;
112     return MemoryOperand(&index);
113   }
114
115   Operand ToOperand(InstructionOperand* op) {
116     if (op->IsRegister()) {
117       return Operand(ToRegister(op));
118     }
119     return ToImmediate(op);
120   }
121
122   Operand ToOperand32(InstructionOperand* op) {
123     if (op->IsRegister()) {
124       return Operand(ToRegister(op).W());
125     }
126     return ToImmediate(op);
127   }
128
129   Operand ToImmediate(InstructionOperand* operand) {
130     Constant constant = ToConstant(operand);
131     switch (constant.type()) {
132       case Constant::kInt32:
133         return Operand(constant.ToInt32());
134       case Constant::kInt64:
135         return Operand(constant.ToInt64());
136       case Constant::kFloat32:
137         return Operand(
138             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
139       case Constant::kFloat64:
140         return Operand(
141             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
142       case Constant::kExternalReference:
143         return Operand(constant.ToExternalReference());
144       case Constant::kHeapObject:
145         return Operand(constant.ToHeapObject());
146     }
147     UNREACHABLE();
148     return Operand(-1);
149   }
150
151   MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const {
152     DCHECK(op != NULL);
153     DCHECK(!op->IsRegister());
154     DCHECK(!op->IsDoubleRegister());
155     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
156     // The linkage computes where all spill slots are located.
157     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
158     return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
159                       offset.offset());
160   }
161 };
162
163
164 #define ASSEMBLE_SHIFT(asm_instr, width)                                       \
165   do {                                                                         \
166     if (instr->InputAt(1)->IsRegister()) {                                     \
167       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0),       \
168                    i.InputRegister##width(1));                                 \
169     } else {                                                                   \
170       int64_t imm = i.InputOperand##width(1).immediate().value();              \
171       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0), imm); \
172     }                                                                          \
173   } while (0)
174
175
176 #define ASSEMBLE_TEST_AND_BRANCH(asm_instr, width)             \
177   do {                                                         \
178     bool fallthrough = IsNextInAssemblyOrder(i.InputRpo(3));   \
179     __ asm_instr(i.InputRegister##width(0), i.InputInt6(1),    \
180                  code_->GetLabel(i.InputRpo(2)));              \
181     if (!fallthrough) __ B(code_->GetLabel(i.InputRpo(3)));    \
182   } while (0)
183
184
185 // Assembles an instruction after register allocation, producing machine code.
186 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
187   Arm64OperandConverter i(this, instr);
188   InstructionCode opcode = instr->opcode();
189   switch (ArchOpcodeField::decode(opcode)) {
190     case kArchCallCodeObject: {
191       EnsureSpaceForLazyDeopt();
192       if (instr->InputAt(0)->IsImmediate()) {
193         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
194                 RelocInfo::CODE_TARGET);
195       } else {
196         Register target = i.InputRegister(0);
197         __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
198         __ Call(target);
199       }
200       AddSafepointAndDeopt(instr);
201       break;
202     }
203     case kArchCallJSFunction: {
204       EnsureSpaceForLazyDeopt();
205       Register func = i.InputRegister(0);
206       if (FLAG_debug_code) {
207         // Check the function's context matches the context argument.
208         UseScratchRegisterScope scope(masm());
209         Register temp = scope.AcquireX();
210         __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset));
211         __ cmp(cp, temp);
212         __ Assert(eq, kWrongFunctionContext);
213       }
214       __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
215       __ Call(x10);
216       AddSafepointAndDeopt(instr);
217       break;
218     }
219     case kArchJmp:
220       __ B(code_->GetLabel(i.InputRpo(0)));
221       break;
222     case kArchNop:
223       // don't emit code for nops.
224       break;
225     case kArchRet:
226       AssembleReturn();
227       break;
228     case kArchStackPointer:
229       __ mov(i.OutputRegister(), masm()->StackPointer());
230       break;
231     case kArchTruncateDoubleToI:
232       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
233       break;
234     case kArm64Float64Ceil:
235       __ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
236       break;
237     case kArm64Float64Floor:
238       __ Frintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
239       break;
240     case kArm64Float64RoundTruncate:
241       __ Frintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
242       break;
243     case kArm64Float64RoundTiesAway:
244       __ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
245       break;
246     case kArm64Add:
247       __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
248       break;
249     case kArm64Add32:
250       if (FlagsModeField::decode(opcode) != kFlags_none) {
251         __ Adds(i.OutputRegister32(), i.InputRegister32(0),
252                 i.InputOperand2_32(1));
253       } else {
254         __ Add(i.OutputRegister32(), i.InputRegister32(0),
255                i.InputOperand2_32(1));
256       }
257       break;
258     case kArm64And:
259       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
260       break;
261     case kArm64And32:
262       __ And(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
263       break;
264     case kArm64Bic:
265       __ Bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
266       break;
267     case kArm64Bic32:
268       __ Bic(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
269       break;
270     case kArm64Mul:
271       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
272       break;
273     case kArm64Mul32:
274       __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
275       break;
276     case kArm64Smull:
277       __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
278       break;
279     case kArm64Umull:
280       __ Umull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
281       break;
282     case kArm64Madd:
283       __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
284               i.InputRegister(2));
285       break;
286     case kArm64Madd32:
287       __ Madd(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
288               i.InputRegister32(2));
289       break;
290     case kArm64Msub:
291       __ Msub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
292               i.InputRegister(2));
293       break;
294     case kArm64Msub32:
295       __ Msub(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
296               i.InputRegister32(2));
297       break;
298     case kArm64Mneg:
299       __ Mneg(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
300       break;
301     case kArm64Mneg32:
302       __ Mneg(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
303       break;
304     case kArm64Idiv:
305       __ Sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
306       break;
307     case kArm64Idiv32:
308       __ Sdiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
309       break;
310     case kArm64Udiv:
311       __ Udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
312       break;
313     case kArm64Udiv32:
314       __ Udiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
315       break;
316     case kArm64Imod: {
317       UseScratchRegisterScope scope(masm());
318       Register temp = scope.AcquireX();
319       __ Sdiv(temp, i.InputRegister(0), i.InputRegister(1));
320       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
321       break;
322     }
323     case kArm64Imod32: {
324       UseScratchRegisterScope scope(masm());
325       Register temp = scope.AcquireW();
326       __ Sdiv(temp, i.InputRegister32(0), i.InputRegister32(1));
327       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
328               i.InputRegister32(0));
329       break;
330     }
331     case kArm64Umod: {
332       UseScratchRegisterScope scope(masm());
333       Register temp = scope.AcquireX();
334       __ Udiv(temp, i.InputRegister(0), i.InputRegister(1));
335       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
336       break;
337     }
338     case kArm64Umod32: {
339       UseScratchRegisterScope scope(masm());
340       Register temp = scope.AcquireW();
341       __ Udiv(temp, i.InputRegister32(0), i.InputRegister32(1));
342       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
343               i.InputRegister32(0));
344       break;
345     }
346     // TODO(dcarney): use mvn instr??
347     case kArm64Not:
348       __ Orn(i.OutputRegister(), xzr, i.InputOperand(0));
349       break;
350     case kArm64Not32:
351       __ Orn(i.OutputRegister32(), wzr, i.InputOperand32(0));
352       break;
353     case kArm64Neg:
354       __ Neg(i.OutputRegister(), i.InputOperand(0));
355       break;
356     case kArm64Neg32:
357       __ Neg(i.OutputRegister32(), i.InputOperand32(0));
358       break;
359     case kArm64Or:
360       __ Orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
361       break;
362     case kArm64Or32:
363       __ Orr(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
364       break;
365     case kArm64Orn:
366       __ Orn(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
367       break;
368     case kArm64Orn32:
369       __ Orn(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
370       break;
371     case kArm64Eor:
372       __ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
373       break;
374     case kArm64Eor32:
375       __ Eor(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
376       break;
377     case kArm64Eon:
378       __ Eon(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
379       break;
380     case kArm64Eon32:
381       __ Eon(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
382       break;
383     case kArm64Sub:
384       __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
385       break;
386     case kArm64Sub32:
387       if (FlagsModeField::decode(opcode) != kFlags_none) {
388         __ Subs(i.OutputRegister32(), i.InputRegister32(0),
389                 i.InputOperand2_32(1));
390       } else {
391         __ Sub(i.OutputRegister32(), i.InputRegister32(0),
392                i.InputOperand2_32(1));
393       }
394       break;
395     case kArm64Lsl:
396       ASSEMBLE_SHIFT(Lsl, 64);
397       break;
398     case kArm64Lsl32:
399       ASSEMBLE_SHIFT(Lsl, 32);
400       break;
401     case kArm64Lsr:
402       ASSEMBLE_SHIFT(Lsr, 64);
403       break;
404     case kArm64Lsr32:
405       ASSEMBLE_SHIFT(Lsr, 32);
406       break;
407     case kArm64Asr:
408       ASSEMBLE_SHIFT(Asr, 64);
409       break;
410     case kArm64Asr32:
411       ASSEMBLE_SHIFT(Asr, 32);
412       break;
413     case kArm64Ror:
414       ASSEMBLE_SHIFT(Ror, 64);
415       break;
416     case kArm64Ror32:
417       ASSEMBLE_SHIFT(Ror, 32);
418       break;
419     case kArm64Mov32:
420       __ Mov(i.OutputRegister32(), i.InputRegister32(0));
421       break;
422     case kArm64Sxtw:
423       __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
424       break;
425     case kArm64Ubfx:
426       __ Ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
427               i.InputInt8(2));
428       break;
429     case kArm64Ubfx32:
430       __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt8(1),
431               i.InputInt8(2));
432       break;
433     case kArm64Tbz:
434       ASSEMBLE_TEST_AND_BRANCH(Tbz, 64);
435       break;
436     case kArm64Tbz32:
437       ASSEMBLE_TEST_AND_BRANCH(Tbz, 32);
438       break;
439     case kArm64Tbnz:
440       ASSEMBLE_TEST_AND_BRANCH(Tbnz, 64);
441       break;
442     case kArm64Tbnz32:
443       ASSEMBLE_TEST_AND_BRANCH(Tbnz, 32);
444       break;
445     case kArm64Claim: {
446       int words = MiscField::decode(instr->opcode());
447       __ Claim(words);
448       break;
449     }
450     case kArm64Poke: {
451       int slot = MiscField::decode(instr->opcode());
452       Operand operand(slot * kPointerSize);
453       __ Poke(i.InputRegister(0), operand);
454       break;
455     }
456     case kArm64PokePairZero: {
457       // TODO(dcarney): test slot offset and register order.
458       int slot = MiscField::decode(instr->opcode()) - 1;
459       __ PokePair(i.InputRegister(0), xzr, slot * kPointerSize);
460       break;
461     }
462     case kArm64PokePair: {
463       int slot = MiscField::decode(instr->opcode()) - 1;
464       __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize);
465       break;
466     }
467     case kArm64Cmp:
468       __ Cmp(i.InputRegister(0), i.InputOperand(1));
469       break;
470     case kArm64Cmp32:
471       __ Cmp(i.InputRegister32(0), i.InputOperand32(1));
472       break;
473     case kArm64Cmn:
474       __ Cmn(i.InputRegister(0), i.InputOperand(1));
475       break;
476     case kArm64Cmn32:
477       __ Cmn(i.InputRegister32(0), i.InputOperand32(1));
478       break;
479     case kArm64Tst:
480       __ Tst(i.InputRegister(0), i.InputOperand(1));
481       break;
482     case kArm64Tst32:
483       __ Tst(i.InputRegister32(0), i.InputOperand32(1));
484       break;
485     case kArm64Float64Cmp:
486       __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
487       break;
488     case kArm64Float64Add:
489       __ Fadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
490               i.InputDoubleRegister(1));
491       break;
492     case kArm64Float64Sub:
493       __ Fsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
494               i.InputDoubleRegister(1));
495       break;
496     case kArm64Float64Mul:
497       __ Fmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
498               i.InputDoubleRegister(1));
499       break;
500     case kArm64Float64Div:
501       __ Fdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
502               i.InputDoubleRegister(1));
503       break;
504     case kArm64Float64Mod: {
505       // TODO(dcarney): implement directly. See note in lithium-codegen-arm64.cc
506       FrameScope scope(masm(), StackFrame::MANUAL);
507       DCHECK(d0.is(i.InputDoubleRegister(0)));
508       DCHECK(d1.is(i.InputDoubleRegister(1)));
509       DCHECK(d0.is(i.OutputDoubleRegister()));
510       // TODO(dcarney): make sure this saves all relevant registers.
511       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
512                        0, 2);
513       break;
514     }
515     case kArm64Float64Sqrt:
516       __ Fsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
517       break;
518     case kArm64Float32ToFloat64:
519       __ Fcvt(i.OutputDoubleRegister(), i.InputDoubleRegister(0).S());
520       break;
521     case kArm64Float64ToFloat32:
522       __ Fcvt(i.OutputDoubleRegister().S(), i.InputDoubleRegister(0));
523       break;
524     case kArm64Float64ToInt32:
525       __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
526       break;
527     case kArm64Float64ToUint32:
528       __ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
529       break;
530     case kArm64Int32ToFloat64:
531       __ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
532       break;
533     case kArm64Uint32ToFloat64:
534       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
535       break;
536     case kArm64Ldrb:
537       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
538       break;
539     case kArm64Ldrsb:
540       __ Ldrsb(i.OutputRegister(), i.MemoryOperand());
541       break;
542     case kArm64Strb:
543       __ Strb(i.InputRegister(2), i.MemoryOperand());
544       break;
545     case kArm64Ldrh:
546       __ Ldrh(i.OutputRegister(), i.MemoryOperand());
547       break;
548     case kArm64Ldrsh:
549       __ Ldrsh(i.OutputRegister(), i.MemoryOperand());
550       break;
551     case kArm64Strh:
552       __ Strh(i.InputRegister(2), i.MemoryOperand());
553       break;
554     case kArm64LdrW:
555       __ Ldr(i.OutputRegister32(), i.MemoryOperand());
556       break;
557     case kArm64StrW:
558       __ Str(i.InputRegister32(2), i.MemoryOperand());
559       break;
560     case kArm64Ldr:
561       __ Ldr(i.OutputRegister(), i.MemoryOperand());
562       break;
563     case kArm64Str:
564       __ Str(i.InputRegister(2), i.MemoryOperand());
565       break;
566     case kArm64LdrS:
567       __ Ldr(i.OutputDoubleRegister().S(), i.MemoryOperand());
568       break;
569     case kArm64StrS:
570       __ Str(i.InputDoubleRegister(2).S(), i.MemoryOperand());
571       break;
572     case kArm64LdrD:
573       __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
574       break;
575     case kArm64StrD:
576       __ Str(i.InputDoubleRegister(2), i.MemoryOperand());
577       break;
578     case kArm64StoreWriteBarrier: {
579       Register object = i.InputRegister(0);
580       Register index = i.InputRegister(1);
581       Register value = i.InputRegister(2);
582       __ Add(index, object, Operand(index, SXTW));
583       __ Str(value, MemOperand(index));
584       SaveFPRegsMode mode =
585           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
586       // TODO(dcarney): we shouldn't test write barriers from c calls.
587       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
588       UseScratchRegisterScope scope(masm());
589       Register temp = no_reg;
590       if (csp.is(masm()->StackPointer())) {
591         temp = scope.AcquireX();
592         lr_status = kLRHasBeenSaved;
593         __ Push(lr, temp);  // Need to push a pair
594       }
595       __ RecordWrite(object, index, value, lr_status, mode);
596       if (csp.is(masm()->StackPointer())) {
597         __ Pop(temp, lr);
598       }
599       break;
600     }
601   }
602 }
603
604
605 // Assemble branches after this instruction.
606 void CodeGenerator::AssembleArchBranch(Instruction* instr,
607                                        FlagsCondition condition) {
608   Arm64OperandConverter i(this, instr);
609   Label done;
610
611   // Emit a branch. The true and false targets are always the last two inputs
612   // to the instruction.
613   BasicBlock::RpoNumber tblock =
614       i.InputRpo(static_cast<int>(instr->InputCount()) - 2);
615   BasicBlock::RpoNumber fblock =
616       i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
617   bool fallthru = IsNextInAssemblyOrder(fblock);
618   Label* tlabel = code()->GetLabel(tblock);
619   Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
620   switch (condition) {
621     case kUnorderedEqual:
622       __ B(vs, flabel);
623     // Fall through.
624     case kEqual:
625       __ B(eq, tlabel);
626       break;
627     case kUnorderedNotEqual:
628       __ B(vs, tlabel);
629     // Fall through.
630     case kNotEqual:
631       __ B(ne, tlabel);
632       break;
633     case kSignedLessThan:
634       __ B(lt, tlabel);
635       break;
636     case kSignedGreaterThanOrEqual:
637       __ B(ge, tlabel);
638       break;
639     case kSignedLessThanOrEqual:
640       __ B(le, tlabel);
641       break;
642     case kSignedGreaterThan:
643       __ B(gt, tlabel);
644       break;
645     case kUnorderedLessThan:
646       __ B(vs, flabel);
647     // Fall through.
648     case kUnsignedLessThan:
649       __ B(lo, tlabel);
650       break;
651     case kUnorderedGreaterThanOrEqual:
652       __ B(vs, tlabel);
653     // Fall through.
654     case kUnsignedGreaterThanOrEqual:
655       __ B(hs, tlabel);
656       break;
657     case kUnorderedLessThanOrEqual:
658       __ B(vs, flabel);
659     // Fall through.
660     case kUnsignedLessThanOrEqual:
661       __ B(ls, tlabel);
662       break;
663     case kUnorderedGreaterThan:
664       __ B(vs, tlabel);
665     // Fall through.
666     case kUnsignedGreaterThan:
667       __ B(hi, tlabel);
668       break;
669     case kOverflow:
670       __ B(vs, tlabel);
671       break;
672     case kNotOverflow:
673       __ B(vc, tlabel);
674       break;
675   }
676   if (!fallthru) __ B(flabel);  // no fallthru to flabel.
677   __ Bind(&done);
678 }
679
680
681 // Assemble boolean materializations after this instruction.
682 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
683                                         FlagsCondition condition) {
684   Arm64OperandConverter i(this, instr);
685   Label done;
686
687   // Materialize a full 64-bit 1 or 0 value. The result register is always the
688   // last output of the instruction.
689   Label check;
690   DCHECK_NE(0, instr->OutputCount());
691   Register reg = i.OutputRegister(instr->OutputCount() - 1);
692   Condition cc = nv;
693   switch (condition) {
694     case kUnorderedEqual:
695       __ B(vc, &check);
696       __ Mov(reg, 0);
697       __ B(&done);
698     // Fall through.
699     case kEqual:
700       cc = eq;
701       break;
702     case kUnorderedNotEqual:
703       __ B(vc, &check);
704       __ Mov(reg, 1);
705       __ B(&done);
706     // Fall through.
707     case kNotEqual:
708       cc = ne;
709       break;
710     case kSignedLessThan:
711       cc = lt;
712       break;
713     case kSignedGreaterThanOrEqual:
714       cc = ge;
715       break;
716     case kSignedLessThanOrEqual:
717       cc = le;
718       break;
719     case kSignedGreaterThan:
720       cc = gt;
721       break;
722     case kUnorderedLessThan:
723       __ B(vc, &check);
724       __ Mov(reg, 0);
725       __ B(&done);
726     // Fall through.
727     case kUnsignedLessThan:
728       cc = lo;
729       break;
730     case kUnorderedGreaterThanOrEqual:
731       __ B(vc, &check);
732       __ Mov(reg, 1);
733       __ B(&done);
734     // Fall through.
735     case kUnsignedGreaterThanOrEqual:
736       cc = hs;
737       break;
738     case kUnorderedLessThanOrEqual:
739       __ B(vc, &check);
740       __ Mov(reg, 0);
741       __ B(&done);
742     // Fall through.
743     case kUnsignedLessThanOrEqual:
744       cc = ls;
745       break;
746     case kUnorderedGreaterThan:
747       __ B(vc, &check);
748       __ Mov(reg, 1);
749       __ B(&done);
750     // Fall through.
751     case kUnsignedGreaterThan:
752       cc = hi;
753       break;
754     case kOverflow:
755       cc = vs;
756       break;
757     case kNotOverflow:
758       cc = vc;
759       break;
760   }
761   __ bind(&check);
762   __ Cset(reg, cc);
763   __ Bind(&done);
764 }
765
766
767 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
768   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
769       isolate(), deoptimization_id, Deoptimizer::LAZY);
770   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
771 }
772
773
774 // TODO(dcarney): increase stack slots in frame once before first use.
775 static int AlignedStackSlots(int stack_slots) {
776   if (stack_slots & 1) stack_slots++;
777   return stack_slots;
778 }
779
780
781 void CodeGenerator::AssemblePrologue() {
782   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
783   if (descriptor->kind() == CallDescriptor::kCallAddress) {
784     __ SetStackPointer(csp);
785     __ Push(lr, fp);
786     __ Mov(fp, csp);
787     // TODO(dcarney): correct callee saved registers.
788     __ PushCalleeSavedRegisters();
789     frame()->SetRegisterSaveAreaSize(20 * kPointerSize);
790   } else if (descriptor->IsJSFunctionCall()) {
791     CompilationInfo* info = this->info();
792     __ SetStackPointer(jssp);
793     __ Prologue(info->IsCodePreAgingActive());
794     frame()->SetRegisterSaveAreaSize(
795         StandardFrameConstants::kFixedFrameSizeFromFp);
796
797     // Sloppy mode functions and builtins need to replace the receiver with the
798     // global proxy when called as functions (without an explicit receiver
799     // object).
800     // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
801     if (info->strict_mode() == SLOPPY && !info->is_native()) {
802       Label ok;
803       // +2 for return address and saved frame pointer.
804       int receiver_slot = info->scope()->num_parameters() + 2;
805       __ Ldr(x10, MemOperand(fp, receiver_slot * kXRegSize));
806       __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
807       __ Ldr(x10, GlobalObjectMemOperand());
808       __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
809       __ Str(x10, MemOperand(fp, receiver_slot * kXRegSize));
810       __ Bind(&ok);
811     }
812
813   } else {
814     __ SetStackPointer(jssp);
815     __ StubPrologue();
816     frame()->SetRegisterSaveAreaSize(
817         StandardFrameConstants::kFixedFrameSizeFromFp);
818   }
819   int stack_slots = frame()->GetSpillSlotCount();
820   if (stack_slots > 0) {
821     Register sp = __ StackPointer();
822     if (!sp.Is(csp)) {
823       __ Sub(sp, sp, stack_slots * kPointerSize);
824     }
825     __ Sub(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
826   }
827 }
828
829
830 void CodeGenerator::AssembleReturn() {
831   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
832   if (descriptor->kind() == CallDescriptor::kCallAddress) {
833     if (frame()->GetRegisterSaveAreaSize() > 0) {
834       // Remove this frame's spill slots first.
835       int stack_slots = frame()->GetSpillSlotCount();
836       if (stack_slots > 0) {
837         __ Add(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
838       }
839       // Restore registers.
840       // TODO(dcarney): correct callee saved registers.
841       __ PopCalleeSavedRegisters();
842     }
843     __ Mov(csp, fp);
844     __ Pop(fp, lr);
845     __ Ret();
846   } else {
847     __ Mov(jssp, fp);
848     __ Pop(fp, lr);
849     int pop_count = descriptor->IsJSFunctionCall()
850                         ? static_cast<int>(descriptor->JSParameterCount())
851                         : 0;
852     __ Drop(pop_count);
853     __ Ret();
854   }
855 }
856
857
858 void CodeGenerator::AssembleMove(InstructionOperand* source,
859                                  InstructionOperand* destination) {
860   Arm64OperandConverter g(this, NULL);
861   // Dispatch on the source and destination operand kinds.  Not all
862   // combinations are possible.
863   if (source->IsRegister()) {
864     DCHECK(destination->IsRegister() || destination->IsStackSlot());
865     Register src = g.ToRegister(source);
866     if (destination->IsRegister()) {
867       __ Mov(g.ToRegister(destination), src);
868     } else {
869       __ Str(src, g.ToMemOperand(destination, masm()));
870     }
871   } else if (source->IsStackSlot()) {
872     MemOperand src = g.ToMemOperand(source, masm());
873     DCHECK(destination->IsRegister() || destination->IsStackSlot());
874     if (destination->IsRegister()) {
875       __ Ldr(g.ToRegister(destination), src);
876     } else {
877       UseScratchRegisterScope scope(masm());
878       Register temp = scope.AcquireX();
879       __ Ldr(temp, src);
880       __ Str(temp, g.ToMemOperand(destination, masm()));
881     }
882   } else if (source->IsConstant()) {
883     Constant src = g.ToConstant(ConstantOperand::cast(source));
884     if (destination->IsRegister() || destination->IsStackSlot()) {
885       UseScratchRegisterScope scope(masm());
886       Register dst = destination->IsRegister() ? g.ToRegister(destination)
887                                                : scope.AcquireX();
888       if (src.type() == Constant::kHeapObject) {
889         __ LoadObject(dst, src.ToHeapObject());
890       } else {
891         __ Mov(dst, g.ToImmediate(source));
892       }
893       if (destination->IsStackSlot()) {
894         __ Str(dst, g.ToMemOperand(destination, masm()));
895       }
896     } else if (src.type() == Constant::kFloat32) {
897       if (destination->IsDoubleRegister()) {
898         FPRegister dst = g.ToDoubleRegister(destination).S();
899         __ Fmov(dst, src.ToFloat32());
900       } else {
901         DCHECK(destination->IsDoubleStackSlot());
902         UseScratchRegisterScope scope(masm());
903         FPRegister temp = scope.AcquireS();
904         __ Fmov(temp, src.ToFloat32());
905         __ Str(temp, g.ToMemOperand(destination, masm()));
906       }
907     } else {
908       DCHECK_EQ(Constant::kFloat64, src.type());
909       if (destination->IsDoubleRegister()) {
910         FPRegister dst = g.ToDoubleRegister(destination);
911         __ Fmov(dst, src.ToFloat64());
912       } else {
913         DCHECK(destination->IsDoubleStackSlot());
914         UseScratchRegisterScope scope(masm());
915         FPRegister temp = scope.AcquireD();
916         __ Fmov(temp, src.ToFloat64());
917         __ Str(temp, g.ToMemOperand(destination, masm()));
918       }
919     }
920   } else if (source->IsDoubleRegister()) {
921     FPRegister src = g.ToDoubleRegister(source);
922     if (destination->IsDoubleRegister()) {
923       FPRegister dst = g.ToDoubleRegister(destination);
924       __ Fmov(dst, src);
925     } else {
926       DCHECK(destination->IsDoubleStackSlot());
927       __ Str(src, g.ToMemOperand(destination, masm()));
928     }
929   } else if (source->IsDoubleStackSlot()) {
930     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
931     MemOperand src = g.ToMemOperand(source, masm());
932     if (destination->IsDoubleRegister()) {
933       __ Ldr(g.ToDoubleRegister(destination), src);
934     } else {
935       UseScratchRegisterScope scope(masm());
936       FPRegister temp = scope.AcquireD();
937       __ Ldr(temp, src);
938       __ Str(temp, g.ToMemOperand(destination, masm()));
939     }
940   } else {
941     UNREACHABLE();
942   }
943 }
944
945
946 void CodeGenerator::AssembleSwap(InstructionOperand* source,
947                                  InstructionOperand* destination) {
948   Arm64OperandConverter g(this, NULL);
949   // Dispatch on the source and destination operand kinds.  Not all
950   // combinations are possible.
951   if (source->IsRegister()) {
952     // Register-register.
953     UseScratchRegisterScope scope(masm());
954     Register temp = scope.AcquireX();
955     Register src = g.ToRegister(source);
956     if (destination->IsRegister()) {
957       Register dst = g.ToRegister(destination);
958       __ Mov(temp, src);
959       __ Mov(src, dst);
960       __ Mov(dst, temp);
961     } else {
962       DCHECK(destination->IsStackSlot());
963       MemOperand dst = g.ToMemOperand(destination, masm());
964       __ Mov(temp, src);
965       __ Ldr(src, dst);
966       __ Str(temp, dst);
967     }
968   } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
969     UseScratchRegisterScope scope(masm());
970     CPURegister temp_0 = scope.AcquireX();
971     CPURegister temp_1 = scope.AcquireX();
972     MemOperand src = g.ToMemOperand(source, masm());
973     MemOperand dst = g.ToMemOperand(destination, masm());
974     __ Ldr(temp_0, src);
975     __ Ldr(temp_1, dst);
976     __ Str(temp_0, dst);
977     __ Str(temp_1, src);
978   } else if (source->IsDoubleRegister()) {
979     UseScratchRegisterScope scope(masm());
980     FPRegister temp = scope.AcquireD();
981     FPRegister src = g.ToDoubleRegister(source);
982     if (destination->IsDoubleRegister()) {
983       FPRegister dst = g.ToDoubleRegister(destination);
984       __ Fmov(temp, src);
985       __ Fmov(src, dst);
986       __ Fmov(dst, temp);
987     } else {
988       DCHECK(destination->IsDoubleStackSlot());
989       MemOperand dst = g.ToMemOperand(destination, masm());
990       __ Fmov(temp, src);
991       __ Ldr(src, dst);
992       __ Str(temp, dst);
993     }
994   } else {
995     // No other combinations are possible.
996     UNREACHABLE();
997   }
998 }
999
1000
1001 void CodeGenerator::AddNopForSmiCodeInlining() { __ movz(xzr, 0); }
1002
1003
1004 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1005   int space_needed = Deoptimizer::patch_size();
1006   if (!info()->IsStub()) {
1007     // Ensure that we have enough space after the previous lazy-bailout
1008     // instruction for patching the code here.
1009     intptr_t current_pc = masm()->pc_offset();
1010
1011     if (current_pc < (last_lazy_deopt_pc_ + space_needed)) {
1012       intptr_t padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1013       DCHECK((padding_size % kInstructionSize) == 0);
1014       InstructionAccurateScope instruction_accurate(
1015           masm(), padding_size / kInstructionSize);
1016
1017       while (padding_size > 0) {
1018         __ nop();
1019         padding_size -= kInstructionSize;
1020       }
1021     }
1022   }
1023   MarkLazyDeoptSite();
1024 }
1025
1026 #undef __
1027
1028 }  // namespace compiler
1029 }  // namespace internal
1030 }  // namespace v8