1ff7ea3acc65e05cf0ca29420b308efcb93d6e23
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / arm / code-generator-arm.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/arm/macro-assembler-arm.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/scopes.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17 #define __ masm()->
18
19
20 #define kScratchReg r9
21
22
23 // Adds Arm-specific methods to convert InstructionOperands.
24 class ArmOperandConverter FINAL : public InstructionOperandConverter {
25  public:
26   ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
27       : InstructionOperandConverter(gen, instr) {}
28
29   SwVfpRegister OutputFloat32Register(int index = 0) {
30     return ToFloat32Register(instr_->OutputAt(index));
31   }
32
33   SwVfpRegister InputFloat32Register(int index) {
34     return ToFloat32Register(instr_->InputAt(index));
35   }
36
37   SwVfpRegister ToFloat32Register(InstructionOperand* op) {
38     return ToFloat64Register(op).low();
39   }
40
41   LowDwVfpRegister OutputFloat64Register(int index = 0) {
42     return ToFloat64Register(instr_->OutputAt(index));
43   }
44
45   LowDwVfpRegister InputFloat64Register(int index) {
46     return ToFloat64Register(instr_->InputAt(index));
47   }
48
49   LowDwVfpRegister ToFloat64Register(InstructionOperand* op) {
50     return LowDwVfpRegister::from_code(ToDoubleRegister(op).code());
51   }
52
53   SBit OutputSBit() const {
54     switch (instr_->flags_mode()) {
55       case kFlags_branch:
56       case kFlags_set:
57         return SetCC;
58       case kFlags_none:
59         return LeaveCC;
60     }
61     UNREACHABLE();
62     return LeaveCC;
63   }
64
65   Operand InputImmediate(int index) {
66     Constant constant = ToConstant(instr_->InputAt(index));
67     switch (constant.type()) {
68       case Constant::kInt32:
69         return Operand(constant.ToInt32());
70       case Constant::kFloat32:
71         return Operand(
72             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
73       case Constant::kFloat64:
74         return Operand(
75             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
76       case Constant::kInt64:
77       case Constant::kExternalReference:
78       case Constant::kHeapObject:
79       case Constant::kRpoNumber:
80         break;
81     }
82     UNREACHABLE();
83     return Operand::Zero();
84   }
85
86   Operand InputOperand2(int first_index) {
87     const int index = first_index;
88     switch (AddressingModeField::decode(instr_->opcode())) {
89       case kMode_None:
90       case kMode_Offset_RI:
91       case kMode_Offset_RR:
92         break;
93       case kMode_Operand2_I:
94         return InputImmediate(index + 0);
95       case kMode_Operand2_R:
96         return Operand(InputRegister(index + 0));
97       case kMode_Operand2_R_ASR_I:
98         return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1));
99       case kMode_Operand2_R_ASR_R:
100         return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1));
101       case kMode_Operand2_R_LSL_I:
102         return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1));
103       case kMode_Operand2_R_LSL_R:
104         return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1));
105       case kMode_Operand2_R_LSR_I:
106         return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
107       case kMode_Operand2_R_LSR_R:
108         return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
109       case kMode_Operand2_R_ROR_I:
110         return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
111       case kMode_Operand2_R_ROR_R:
112         return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
113     }
114     UNREACHABLE();
115     return Operand::Zero();
116   }
117
118   MemOperand InputOffset(int* first_index) {
119     const int index = *first_index;
120     switch (AddressingModeField::decode(instr_->opcode())) {
121       case kMode_None:
122       case kMode_Operand2_I:
123       case kMode_Operand2_R:
124       case kMode_Operand2_R_ASR_I:
125       case kMode_Operand2_R_ASR_R:
126       case kMode_Operand2_R_LSL_I:
127       case kMode_Operand2_R_LSL_R:
128       case kMode_Operand2_R_LSR_I:
129       case kMode_Operand2_R_LSR_R:
130       case kMode_Operand2_R_ROR_I:
131       case kMode_Operand2_R_ROR_R:
132         break;
133       case kMode_Offset_RI:
134         *first_index += 2;
135         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
136       case kMode_Offset_RR:
137         *first_index += 2;
138         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
139     }
140     UNREACHABLE();
141     return MemOperand(r0);
142   }
143
144   MemOperand InputOffset(int first_index = 0) {
145     return InputOffset(&first_index);
146   }
147
148   MemOperand ToMemOperand(InstructionOperand* op) const {
149     DCHECK(op != NULL);
150     DCHECK(!op->IsRegister());
151     DCHECK(!op->IsDoubleRegister());
152     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
153     // The linkage computes where all spill slots are located.
154     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
155     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
156   }
157 };
158
159
160 namespace {
161
162 class OutOfLineLoadFloat32 FINAL : public OutOfLineCode {
163  public:
164   OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
165       : OutOfLineCode(gen), result_(result) {}
166
167   void Generate() FINAL {
168     __ vmov(result_, std::numeric_limits<float>::quiet_NaN());
169   }
170
171  private:
172   SwVfpRegister const result_;
173 };
174
175
176 class OutOfLineLoadFloat64 FINAL : public OutOfLineCode {
177  public:
178   OutOfLineLoadFloat64(CodeGenerator* gen, DwVfpRegister result)
179       : OutOfLineCode(gen), result_(result) {}
180
181   void Generate() FINAL {
182     __ vmov(result_, std::numeric_limits<double>::quiet_NaN(), kScratchReg);
183   }
184
185  private:
186   DwVfpRegister const result_;
187 };
188
189
190 class OutOfLineLoadInteger FINAL : public OutOfLineCode {
191  public:
192   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
193       : OutOfLineCode(gen), result_(result) {}
194
195   void Generate() FINAL { __ mov(result_, Operand::Zero()); }
196
197  private:
198   Register const result_;
199 };
200
201
202 Condition FlagsConditionToCondition(FlagsCondition condition) {
203   switch (condition) {
204     case kEqual:
205       return eq;
206     case kNotEqual:
207       return ne;
208     case kSignedLessThan:
209       return lt;
210     case kSignedGreaterThanOrEqual:
211       return ge;
212     case kSignedLessThanOrEqual:
213       return le;
214     case kSignedGreaterThan:
215       return gt;
216     case kUnsignedLessThan:
217       return lo;
218     case kUnsignedGreaterThanOrEqual:
219       return hs;
220     case kUnsignedLessThanOrEqual:
221       return ls;
222     case kUnsignedGreaterThan:
223       return hi;
224     case kOverflow:
225       return vs;
226     case kNotOverflow:
227       return vc;
228     case kUnorderedEqual:
229     case kUnorderedNotEqual:
230       break;
231   }
232   UNREACHABLE();
233   return kNoCondition;
234 }
235
236 }  // namespace
237
238
239 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width)                           \
240   do {                                                               \
241     auto result = i.OutputFloat##width##Register();                  \
242     auto offset = i.InputRegister(0);                                \
243     if (instr->InputAt(1)->IsRegister()) {                           \
244       __ cmp(offset, i.InputRegister(1));                            \
245     } else {                                                         \
246       __ cmp(offset, i.InputImmediate(1));                           \
247     }                                                                \
248     auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \
249     __ b(hs, ool->entry());                                          \
250     __ vldr(result, i.InputOffset(2));                               \
251     __ bind(ool->exit());                                            \
252     DCHECK_EQ(LeaveCC, i.OutputSBit());                              \
253   } while (0)
254
255
256 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                \
257   do {                                                          \
258     auto result = i.OutputRegister();                           \
259     auto offset = i.InputRegister(0);                           \
260     if (instr->InputAt(1)->IsRegister()) {                      \
261       __ cmp(offset, i.InputRegister(1));                       \
262     } else {                                                    \
263       __ cmp(offset, i.InputImmediate(1));                      \
264     }                                                           \
265     auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
266     __ b(hs, ool->entry());                                     \
267     __ asm_instr(result, i.InputOffset(2));                     \
268     __ bind(ool->exit());                                       \
269     DCHECK_EQ(LeaveCC, i.OutputSBit());                         \
270   } while (0)
271
272
273 #define ASSEMBLE_CHECKED_STORE_FLOAT(width)        \
274   do {                                             \
275     auto offset = i.InputRegister(0);              \
276     if (instr->InputAt(1)->IsRegister()) {         \
277       __ cmp(offset, i.InputRegister(1));          \
278     } else {                                       \
279       __ cmp(offset, i.InputImmediate(1));         \
280     }                                              \
281     auto value = i.InputFloat##width##Register(2); \
282     __ vstr(value, i.InputOffset(3), lo);          \
283     DCHECK_EQ(LeaveCC, i.OutputSBit());            \
284   } while (0)
285
286
287 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
288   do {                                            \
289     auto offset = i.InputRegister(0);             \
290     if (instr->InputAt(1)->IsRegister()) {        \
291       __ cmp(offset, i.InputRegister(1));         \
292     } else {                                      \
293       __ cmp(offset, i.InputImmediate(1));        \
294     }                                             \
295     auto value = i.InputRegister(2);              \
296     __ asm_instr(value, i.InputOffset(3), lo);    \
297     DCHECK_EQ(LeaveCC, i.OutputSBit());           \
298   } while (0)
299
300
301 // Assembles an instruction after register allocation, producing machine code.
302 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
303   ArmOperandConverter i(this, instr);
304
305   switch (ArchOpcodeField::decode(instr->opcode())) {
306     case kArchCallCodeObject: {
307       EnsureSpaceForLazyDeopt();
308       if (instr->InputAt(0)->IsImmediate()) {
309         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
310                 RelocInfo::CODE_TARGET);
311       } else {
312         __ add(ip, i.InputRegister(0),
313                Operand(Code::kHeaderSize - kHeapObjectTag));
314         __ Call(ip);
315       }
316       AddSafepointAndDeopt(instr);
317       DCHECK_EQ(LeaveCC, i.OutputSBit());
318       break;
319     }
320     case kArchCallJSFunction: {
321       EnsureSpaceForLazyDeopt();
322       Register func = i.InputRegister(0);
323       if (FLAG_debug_code) {
324         // Check the function's context matches the context argument.
325         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
326         __ cmp(cp, kScratchReg);
327         __ Assert(eq, kWrongFunctionContext);
328       }
329       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
330       __ Call(ip);
331       AddSafepointAndDeopt(instr);
332       DCHECK_EQ(LeaveCC, i.OutputSBit());
333       break;
334     }
335     case kArchJmp:
336       AssembleArchJump(i.InputRpo(0));
337       DCHECK_EQ(LeaveCC, i.OutputSBit());
338       break;
339     case kArchLookupSwitch:
340       AssembleArchLookupSwitch(instr);
341       DCHECK_EQ(LeaveCC, i.OutputSBit());
342       break;
343     case kArchTableSwitch:
344       AssembleArchTableSwitch(instr);
345       DCHECK_EQ(LeaveCC, i.OutputSBit());
346       break;
347     case kArchNop:
348       // don't emit code for nops.
349       DCHECK_EQ(LeaveCC, i.OutputSBit());
350       break;
351     case kArchRet:
352       AssembleReturn();
353       DCHECK_EQ(LeaveCC, i.OutputSBit());
354       break;
355     case kArchStackPointer:
356       __ mov(i.OutputRegister(), sp);
357       DCHECK_EQ(LeaveCC, i.OutputSBit());
358       break;
359     case kArchTruncateDoubleToI:
360       __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
361       DCHECK_EQ(LeaveCC, i.OutputSBit());
362       break;
363     case kArmAdd:
364       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
365              i.OutputSBit());
366       break;
367     case kArmAnd:
368       __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
369               i.OutputSBit());
370       break;
371     case kArmBic:
372       __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
373              i.OutputSBit());
374       break;
375     case kArmMul:
376       __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
377              i.OutputSBit());
378       break;
379     case kArmMla:
380       __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
381              i.InputRegister(2), i.OutputSBit());
382       break;
383     case kArmMls: {
384       CpuFeatureScope scope(masm(), MLS);
385       __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
386              i.InputRegister(2));
387       DCHECK_EQ(LeaveCC, i.OutputSBit());
388       break;
389     }
390     case kArmSmmul:
391       __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
392       DCHECK_EQ(LeaveCC, i.OutputSBit());
393       break;
394     case kArmSmmla:
395       __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
396                i.InputRegister(2));
397       DCHECK_EQ(LeaveCC, i.OutputSBit());
398       break;
399     case kArmUmull:
400       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
401                i.InputRegister(1), i.OutputSBit());
402       break;
403     case kArmSdiv: {
404       CpuFeatureScope scope(masm(), SUDIV);
405       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
406       DCHECK_EQ(LeaveCC, i.OutputSBit());
407       break;
408     }
409     case kArmUdiv: {
410       CpuFeatureScope scope(masm(), SUDIV);
411       __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
412       DCHECK_EQ(LeaveCC, i.OutputSBit());
413       break;
414     }
415     case kArmMov:
416       __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
417       break;
418     case kArmMvn:
419       __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
420       break;
421     case kArmOrr:
422       __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
423              i.OutputSBit());
424       break;
425     case kArmEor:
426       __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
427              i.OutputSBit());
428       break;
429     case kArmSub:
430       __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
431              i.OutputSBit());
432       break;
433     case kArmRsb:
434       __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
435              i.OutputSBit());
436       break;
437     case kArmBfc: {
438       CpuFeatureScope scope(masm(), ARMv7);
439       __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
440       DCHECK_EQ(LeaveCC, i.OutputSBit());
441       break;
442     }
443     case kArmUbfx: {
444       CpuFeatureScope scope(masm(), ARMv7);
445       __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
446               i.InputInt8(2));
447       DCHECK_EQ(LeaveCC, i.OutputSBit());
448       break;
449     }
450     case kArmSxtb:
451       __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
452       DCHECK_EQ(LeaveCC, i.OutputSBit());
453       break;
454     case kArmSxth:
455       __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
456       DCHECK_EQ(LeaveCC, i.OutputSBit());
457       break;
458     case kArmSxtab:
459       __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
460                i.InputInt32(2));
461       DCHECK_EQ(LeaveCC, i.OutputSBit());
462       break;
463     case kArmSxtah:
464       __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
465                i.InputInt32(2));
466       DCHECK_EQ(LeaveCC, i.OutputSBit());
467       break;
468     case kArmUxtb:
469       __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
470       DCHECK_EQ(LeaveCC, i.OutputSBit());
471       break;
472     case kArmUxth:
473       __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
474       DCHECK_EQ(LeaveCC, i.OutputSBit());
475       break;
476     case kArmUxtab:
477       __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
478                i.InputInt32(2));
479       DCHECK_EQ(LeaveCC, i.OutputSBit());
480       break;
481     case kArmUxtah:
482       __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
483                i.InputInt32(2));
484       DCHECK_EQ(LeaveCC, i.OutputSBit());
485       break;
486     case kArmCmp:
487       __ cmp(i.InputRegister(0), i.InputOperand2(1));
488       DCHECK_EQ(SetCC, i.OutputSBit());
489       break;
490     case kArmCmn:
491       __ cmn(i.InputRegister(0), i.InputOperand2(1));
492       DCHECK_EQ(SetCC, i.OutputSBit());
493       break;
494     case kArmTst:
495       __ tst(i.InputRegister(0), i.InputOperand2(1));
496       DCHECK_EQ(SetCC, i.OutputSBit());
497       break;
498     case kArmTeq:
499       __ teq(i.InputRegister(0), i.InputOperand2(1));
500       DCHECK_EQ(SetCC, i.OutputSBit());
501       break;
502     case kArmVcmpF64:
503       if (instr->InputAt(1)->IsDoubleRegister()) {
504         __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
505                                  i.InputFloat64Register(1));
506       } else {
507         DCHECK(instr->InputAt(1)->IsImmediate());
508         // 0.0 is the only immediate supported by vcmp instructions.
509         DCHECK(i.InputDouble(1) == 0.0);
510         __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
511       }
512       DCHECK_EQ(SetCC, i.OutputSBit());
513       break;
514     case kArmVaddF64:
515       __ vadd(i.OutputFloat64Register(), i.InputFloat64Register(0),
516               i.InputFloat64Register(1));
517       DCHECK_EQ(LeaveCC, i.OutputSBit());
518       break;
519     case kArmVsubF64:
520       __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
521               i.InputFloat64Register(1));
522       DCHECK_EQ(LeaveCC, i.OutputSBit());
523       break;
524     case kArmVmulF64:
525       __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
526               i.InputFloat64Register(1));
527       DCHECK_EQ(LeaveCC, i.OutputSBit());
528       break;
529     case kArmVmlaF64:
530       __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
531               i.InputFloat64Register(2));
532       DCHECK_EQ(LeaveCC, i.OutputSBit());
533       break;
534     case kArmVmlsF64:
535       __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
536               i.InputFloat64Register(2));
537       DCHECK_EQ(LeaveCC, i.OutputSBit());
538       break;
539     case kArmVdivF64:
540       __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
541               i.InputFloat64Register(1));
542       DCHECK_EQ(LeaveCC, i.OutputSBit());
543       break;
544     case kArmVmodF64: {
545       // TODO(bmeurer): We should really get rid of this special instruction,
546       // and generate a CallAddress instruction instead.
547       FrameScope scope(masm(), StackFrame::MANUAL);
548       __ PrepareCallCFunction(0, 2, kScratchReg);
549       __ MovToFloatParameters(i.InputFloat64Register(0),
550                               i.InputFloat64Register(1));
551       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
552                        0, 2);
553       // Move the result in the double result register.
554       __ MovFromFloatResult(i.OutputFloat64Register());
555       DCHECK_EQ(LeaveCC, i.OutputSBit());
556       break;
557     }
558     case kArmVsqrtF64:
559       __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
560       break;
561     case kArmVfloorF64:
562       __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
563       break;
564     case kArmVceilF64:
565       __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
566       break;
567     case kArmVroundTruncateF64:
568       __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
569       break;
570     case kArmVroundTiesAwayF64:
571       __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
572       break;
573     case kArmVnegF64:
574       __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
575       break;
576     case kArmVcvtF32F64: {
577       __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
578       DCHECK_EQ(LeaveCC, i.OutputSBit());
579       break;
580     }
581     case kArmVcvtF64F32: {
582       __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
583       DCHECK_EQ(LeaveCC, i.OutputSBit());
584       break;
585     }
586     case kArmVcvtF64S32: {
587       SwVfpRegister scratch = kScratchDoubleReg.low();
588       __ vmov(scratch, i.InputRegister(0));
589       __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
590       DCHECK_EQ(LeaveCC, i.OutputSBit());
591       break;
592     }
593     case kArmVcvtF64U32: {
594       SwVfpRegister scratch = kScratchDoubleReg.low();
595       __ vmov(scratch, i.InputRegister(0));
596       __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
597       DCHECK_EQ(LeaveCC, i.OutputSBit());
598       break;
599     }
600     case kArmVcvtS32F64: {
601       SwVfpRegister scratch = kScratchDoubleReg.low();
602       __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
603       __ vmov(i.OutputRegister(), scratch);
604       DCHECK_EQ(LeaveCC, i.OutputSBit());
605       break;
606     }
607     case kArmVcvtU32F64: {
608       SwVfpRegister scratch = kScratchDoubleReg.low();
609       __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
610       __ vmov(i.OutputRegister(), scratch);
611       DCHECK_EQ(LeaveCC, i.OutputSBit());
612       break;
613     }
614     case kArmLdrb:
615       __ ldrb(i.OutputRegister(), i.InputOffset());
616       DCHECK_EQ(LeaveCC, i.OutputSBit());
617       break;
618     case kArmLdrsb:
619       __ ldrsb(i.OutputRegister(), i.InputOffset());
620       DCHECK_EQ(LeaveCC, i.OutputSBit());
621       break;
622     case kArmStrb: {
623       int index = 0;
624       MemOperand operand = i.InputOffset(&index);
625       __ strb(i.InputRegister(index), operand);
626       DCHECK_EQ(LeaveCC, i.OutputSBit());
627       break;
628     }
629     case kArmLdrh:
630       __ ldrh(i.OutputRegister(), i.InputOffset());
631       break;
632     case kArmLdrsh:
633       __ ldrsh(i.OutputRegister(), i.InputOffset());
634       break;
635     case kArmStrh: {
636       int index = 0;
637       MemOperand operand = i.InputOffset(&index);
638       __ strh(i.InputRegister(index), operand);
639       DCHECK_EQ(LeaveCC, i.OutputSBit());
640       break;
641     }
642     case kArmLdr:
643       __ ldr(i.OutputRegister(), i.InputOffset());
644       break;
645     case kArmStr: {
646       int index = 0;
647       MemOperand operand = i.InputOffset(&index);
648       __ str(i.InputRegister(index), operand);
649       DCHECK_EQ(LeaveCC, i.OutputSBit());
650       break;
651     }
652     case kArmVldrF32: {
653       __ vldr(i.OutputFloat32Register(), i.InputOffset());
654       DCHECK_EQ(LeaveCC, i.OutputSBit());
655       break;
656     }
657     case kArmVstrF32: {
658       int index = 0;
659       MemOperand operand = i.InputOffset(&index);
660       __ vstr(i.InputFloat32Register(index), operand);
661       DCHECK_EQ(LeaveCC, i.OutputSBit());
662       break;
663     }
664     case kArmVldrF64:
665       __ vldr(i.OutputFloat64Register(), i.InputOffset());
666       DCHECK_EQ(LeaveCC, i.OutputSBit());
667       break;
668     case kArmVstrF64: {
669       int index = 0;
670       MemOperand operand = i.InputOffset(&index);
671       __ vstr(i.InputFloat64Register(index), operand);
672       DCHECK_EQ(LeaveCC, i.OutputSBit());
673       break;
674     }
675     case kArmPush:
676       __ Push(i.InputRegister(0));
677       DCHECK_EQ(LeaveCC, i.OutputSBit());
678       break;
679     case kArmStoreWriteBarrier: {
680       Register object = i.InputRegister(0);
681       Register index = i.InputRegister(1);
682       Register value = i.InputRegister(2);
683       __ add(index, object, index);
684       __ str(value, MemOperand(index));
685       SaveFPRegsMode mode =
686           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
687       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
688       __ RecordWrite(object, index, value, lr_status, mode);
689       DCHECK_EQ(LeaveCC, i.OutputSBit());
690       break;
691     }
692     case kCheckedLoadInt8:
693       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
694       break;
695     case kCheckedLoadUint8:
696       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
697       break;
698     case kCheckedLoadInt16:
699       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
700       break;
701     case kCheckedLoadUint16:
702       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
703       break;
704     case kCheckedLoadWord32:
705       ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
706       break;
707     case kCheckedLoadFloat32:
708       ASSEMBLE_CHECKED_LOAD_FLOAT(32);
709       break;
710     case kCheckedLoadFloat64:
711       ASSEMBLE_CHECKED_LOAD_FLOAT(64);
712       break;
713     case kCheckedStoreWord8:
714       ASSEMBLE_CHECKED_STORE_INTEGER(strb);
715       break;
716     case kCheckedStoreWord16:
717       ASSEMBLE_CHECKED_STORE_INTEGER(strh);
718       break;
719     case kCheckedStoreWord32:
720       ASSEMBLE_CHECKED_STORE_INTEGER(str);
721       break;
722     case kCheckedStoreFloat32:
723       ASSEMBLE_CHECKED_STORE_FLOAT(32);
724       break;
725     case kCheckedStoreFloat64:
726       ASSEMBLE_CHECKED_STORE_FLOAT(64);
727       break;
728   }
729 }
730
731
732 // Assembles branches after an instruction.
733 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
734   ArmOperandConverter i(this, instr);
735   Label* tlabel = branch->true_label;
736   Label* flabel = branch->false_label;
737   Condition cc = FlagsConditionToCondition(branch->condition);
738   __ b(cc, tlabel);
739   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
740 }
741
742
743 void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
744   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
745 }
746
747
748 // Assembles boolean materializations after an instruction.
749 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
750                                         FlagsCondition condition) {
751   ArmOperandConverter i(this, instr);
752
753   // Materialize a full 32-bit 1 or 0 value. The result register is always the
754   // last output of the instruction.
755   DCHECK_NE(0u, instr->OutputCount());
756   Register reg = i.OutputRegister(instr->OutputCount() - 1);
757   Condition cc = FlagsConditionToCondition(condition);
758   __ mov(reg, Operand(0));
759   __ mov(reg, Operand(1), LeaveCC, cc);
760 }
761
762
763 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
764   ArmOperandConverter i(this, instr);
765   Register input = i.InputRegister(0);
766   for (size_t index = 2; index < instr->InputCount(); index += 2) {
767     __ cmp(input, Operand(i.InputInt32(index + 0)));
768     __ b(eq, GetLabel(i.InputRpo(index + 1)));
769   }
770   AssembleArchJump(i.InputRpo(1));
771 }
772
773
774 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
775   ArmOperandConverter i(this, instr);
776   Register input = i.InputRegister(0);
777   size_t const case_count = instr->InputCount() - 2;
778   __ cmp(input, Operand(case_count));
779   __ BlockConstPoolFor(case_count + 2);
780   __ ldr(pc, MemOperand(pc, input, LSL, 2), lo);
781   __ b(GetLabel(i.InputRpo(1)));
782   for (size_t index = 0; index < case_count; ++index) {
783     __ dd(GetLabel(i.InputRpo(index + 2)));
784   }
785 }
786
787
788 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
789   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
790       isolate(), deoptimization_id, Deoptimizer::LAZY);
791   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
792 }
793
794
795 void CodeGenerator::AssemblePrologue() {
796   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
797   int stack_slots = frame()->GetSpillSlotCount();
798   if (descriptor->kind() == CallDescriptor::kCallAddress) {
799     bool saved_pp;
800     if (FLAG_enable_ool_constant_pool) {
801       __ Push(lr, fp, pp);
802       // Adjust FP to point to saved FP.
803       __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
804       saved_pp = true;
805     } else {
806       __ Push(lr, fp);
807       __ mov(fp, sp);
808       saved_pp = false;
809     }
810     const RegList saves = descriptor->CalleeSavedRegisters();
811     if (saves != 0 || saved_pp) {
812       // Save callee-saved registers.
813       int register_save_area_size = saved_pp ? kPointerSize : 0;
814       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
815         if (!((1 << i) & saves)) continue;
816         register_save_area_size += kPointerSize;
817       }
818       frame()->SetRegisterSaveAreaSize(register_save_area_size);
819       __ stm(db_w, sp, saves);
820     }
821   } else if (descriptor->IsJSFunctionCall()) {
822     CompilationInfo* info = this->info();
823     __ Prologue(info->IsCodePreAgingActive());
824     frame()->SetRegisterSaveAreaSize(
825         StandardFrameConstants::kFixedFrameSizeFromFp);
826   } else if (stack_slots > 0) {
827     __ StubPrologue();
828     frame()->SetRegisterSaveAreaSize(
829         StandardFrameConstants::kFixedFrameSizeFromFp);
830   }
831
832   if (info()->is_osr()) {
833     // TurboFan OSR-compiled functions cannot be entered directly.
834     __ Abort(kShouldNotDirectlyEnterOsrFunction);
835
836     // Unoptimized code jumps directly to this entrypoint while the unoptimized
837     // frame is still on the stack. Optimized code uses OSR values directly from
838     // the unoptimized frame. Thus, all that needs to be done is to allocate the
839     // remaining stack slots.
840     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
841     osr_pc_offset_ = __ pc_offset();
842     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
843     stack_slots -= frame()->GetOsrStackSlotCount();
844   }
845
846   if (stack_slots > 0) {
847     __ sub(sp, sp, Operand(stack_slots * kPointerSize));
848   }
849 }
850
851
852 void CodeGenerator::AssembleReturn() {
853   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
854   int stack_slots = frame()->GetSpillSlotCount();
855   if (descriptor->kind() == CallDescriptor::kCallAddress) {
856     if (frame()->GetRegisterSaveAreaSize() > 0) {
857       // Remove this frame's spill slots first.
858       if (stack_slots > 0) {
859         __ add(sp, sp, Operand(stack_slots * kPointerSize));
860       }
861       // Restore registers.
862       const RegList saves = descriptor->CalleeSavedRegisters();
863       if (saves != 0) {
864         __ ldm(ia_w, sp, saves);
865       }
866     }
867     __ LeaveFrame(StackFrame::MANUAL);
868     __ Ret();
869   } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
870     __ LeaveFrame(StackFrame::MANUAL);
871     int pop_count = descriptor->IsJSFunctionCall()
872                         ? static_cast<int>(descriptor->JSParameterCount())
873                         : 0;
874     __ Drop(pop_count);
875     __ Ret();
876   } else {
877     __ Ret();
878   }
879 }
880
881
882 void CodeGenerator::AssembleMove(InstructionOperand* source,
883                                  InstructionOperand* destination) {
884   ArmOperandConverter g(this, NULL);
885   // Dispatch on the source and destination operand kinds.  Not all
886   // combinations are possible.
887   if (source->IsRegister()) {
888     DCHECK(destination->IsRegister() || destination->IsStackSlot());
889     Register src = g.ToRegister(source);
890     if (destination->IsRegister()) {
891       __ mov(g.ToRegister(destination), src);
892     } else {
893       __ str(src, g.ToMemOperand(destination));
894     }
895   } else if (source->IsStackSlot()) {
896     DCHECK(destination->IsRegister() || destination->IsStackSlot());
897     MemOperand src = g.ToMemOperand(source);
898     if (destination->IsRegister()) {
899       __ ldr(g.ToRegister(destination), src);
900     } else {
901       Register temp = kScratchReg;
902       __ ldr(temp, src);
903       __ str(temp, g.ToMemOperand(destination));
904     }
905   } else if (source->IsConstant()) {
906     Constant src = g.ToConstant(source);
907     if (destination->IsRegister() || destination->IsStackSlot()) {
908       Register dst =
909           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
910       switch (src.type()) {
911         case Constant::kInt32:
912           __ mov(dst, Operand(src.ToInt32()));
913           break;
914         case Constant::kInt64:
915           UNREACHABLE();
916           break;
917         case Constant::kFloat32:
918           __ Move(dst,
919                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
920           break;
921         case Constant::kFloat64:
922           __ Move(dst,
923                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
924           break;
925         case Constant::kExternalReference:
926           __ mov(dst, Operand(src.ToExternalReference()));
927           break;
928         case Constant::kHeapObject:
929           __ Move(dst, src.ToHeapObject());
930           break;
931         case Constant::kRpoNumber:
932           UNREACHABLE();  // TODO(dcarney): loading RPO constants on arm.
933           break;
934       }
935       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
936     } else if (src.type() == Constant::kFloat32) {
937       if (destination->IsDoubleStackSlot()) {
938         MemOperand dst = g.ToMemOperand(destination);
939         __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
940         __ str(ip, dst);
941       } else {
942         SwVfpRegister dst = g.ToFloat32Register(destination);
943         __ vmov(dst, src.ToFloat32());
944       }
945     } else {
946       DCHECK_EQ(Constant::kFloat64, src.type());
947       DwVfpRegister dst = destination->IsDoubleRegister()
948                               ? g.ToFloat64Register(destination)
949                               : kScratchDoubleReg;
950       __ vmov(dst, src.ToFloat64(), kScratchReg);
951       if (destination->IsDoubleStackSlot()) {
952         __ vstr(dst, g.ToMemOperand(destination));
953       }
954     }
955   } else if (source->IsDoubleRegister()) {
956     DwVfpRegister src = g.ToDoubleRegister(source);
957     if (destination->IsDoubleRegister()) {
958       DwVfpRegister dst = g.ToDoubleRegister(destination);
959       __ Move(dst, src);
960     } else {
961       DCHECK(destination->IsDoubleStackSlot());
962       __ vstr(src, g.ToMemOperand(destination));
963     }
964   } else if (source->IsDoubleStackSlot()) {
965     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
966     MemOperand src = g.ToMemOperand(source);
967     if (destination->IsDoubleRegister()) {
968       __ vldr(g.ToDoubleRegister(destination), src);
969     } else {
970       DwVfpRegister temp = kScratchDoubleReg;
971       __ vldr(temp, src);
972       __ vstr(temp, g.ToMemOperand(destination));
973     }
974   } else {
975     UNREACHABLE();
976   }
977 }
978
979
980 void CodeGenerator::AssembleSwap(InstructionOperand* source,
981                                  InstructionOperand* destination) {
982   ArmOperandConverter g(this, NULL);
983   // Dispatch on the source and destination operand kinds.  Not all
984   // combinations are possible.
985   if (source->IsRegister()) {
986     // Register-register.
987     Register temp = kScratchReg;
988     Register src = g.ToRegister(source);
989     if (destination->IsRegister()) {
990       Register dst = g.ToRegister(destination);
991       __ Move(temp, src);
992       __ Move(src, dst);
993       __ Move(dst, temp);
994     } else {
995       DCHECK(destination->IsStackSlot());
996       MemOperand dst = g.ToMemOperand(destination);
997       __ mov(temp, src);
998       __ ldr(src, dst);
999       __ str(temp, dst);
1000     }
1001   } else if (source->IsStackSlot()) {
1002     DCHECK(destination->IsStackSlot());
1003     Register temp_0 = kScratchReg;
1004     SwVfpRegister temp_1 = kScratchDoubleReg.low();
1005     MemOperand src = g.ToMemOperand(source);
1006     MemOperand dst = g.ToMemOperand(destination);
1007     __ ldr(temp_0, src);
1008     __ vldr(temp_1, dst);
1009     __ str(temp_0, dst);
1010     __ vstr(temp_1, src);
1011   } else if (source->IsDoubleRegister()) {
1012     DwVfpRegister temp = kScratchDoubleReg;
1013     DwVfpRegister src = g.ToDoubleRegister(source);
1014     if (destination->IsDoubleRegister()) {
1015       DwVfpRegister dst = g.ToDoubleRegister(destination);
1016       __ Move(temp, src);
1017       __ Move(src, dst);
1018       __ Move(dst, temp);
1019     } else {
1020       DCHECK(destination->IsDoubleStackSlot());
1021       MemOperand dst = g.ToMemOperand(destination);
1022       __ Move(temp, src);
1023       __ vldr(src, dst);
1024       __ vstr(temp, dst);
1025     }
1026   } else if (source->IsDoubleStackSlot()) {
1027     DCHECK(destination->IsDoubleStackSlot());
1028     Register temp_0 = kScratchReg;
1029     DwVfpRegister temp_1 = kScratchDoubleReg;
1030     MemOperand src0 = g.ToMemOperand(source);
1031     MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
1032     MemOperand dst0 = g.ToMemOperand(destination);
1033     MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
1034     __ vldr(temp_1, dst0);  // Save destination in temp_1.
1035     __ ldr(temp_0, src0);   // Then use temp_0 to copy source to destination.
1036     __ str(temp_0, dst0);
1037     __ ldr(temp_0, src1);
1038     __ str(temp_0, dst1);
1039     __ vstr(temp_1, src0);
1040   } else {
1041     // No other combinations are possible.
1042     UNREACHABLE();
1043   }
1044 }
1045
1046
1047 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1048   // On 32-bit ARM we emit the jump tables inline.
1049   UNREACHABLE();
1050 }
1051
1052
1053 void CodeGenerator::AddNopForSmiCodeInlining() {
1054   // On 32-bit ARM we do not insert nops for inlined Smi code.
1055 }
1056
1057
1058 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1059   int space_needed = Deoptimizer::patch_size();
1060   if (!info()->IsStub()) {
1061     // Ensure that we have enough space after the previous lazy-bailout
1062     // instruction for patching the code here.
1063     int current_pc = masm()->pc_offset();
1064     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1065       // Block literal pool emission for duration of padding.
1066       v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
1067       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1068       DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1069       while (padding_size > 0) {
1070         __ nop();
1071         padding_size -= v8::internal::Assembler::kInstrSize;
1072       }
1073     }
1074   }
1075   MarkLazyDeoptSite();
1076 }
1077
1078 #undef __
1079
1080 }  // namespace compiler
1081 }  // namespace internal
1082 }  // namespace v8