deps: update v8 to 4.3.61.21
[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(size_t index = 0) {
30     return ToFloat32Register(instr_->OutputAt(index));
31   }
32
33   SwVfpRegister InputFloat32Register(size_t index) {
34     return ToFloat32Register(instr_->InputAt(index));
35   }
36
37   SwVfpRegister ToFloat32Register(InstructionOperand* op) {
38     return ToFloat64Register(op).low();
39   }
40
41   LowDwVfpRegister OutputFloat64Register(size_t index = 0) {
42     return ToFloat64Register(instr_->OutputAt(index));
43   }
44
45   LowDwVfpRegister InputFloat64Register(size_t 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(size_t 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(size_t first_index) {
87     const size_t 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(size_t* first_index) {
119     const size_t 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(size_t 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       RecordCallPosition(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       RecordCallPosition(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 kArchDeoptimize: {
352       int deopt_state_id =
353           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
354       AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
355       break;
356     }
357     case kArchRet:
358       AssembleReturn();
359       DCHECK_EQ(LeaveCC, i.OutputSBit());
360       break;
361     case kArchStackPointer:
362       __ mov(i.OutputRegister(), sp);
363       DCHECK_EQ(LeaveCC, i.OutputSBit());
364       break;
365     case kArchTruncateDoubleToI:
366       __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
367       DCHECK_EQ(LeaveCC, i.OutputSBit());
368       break;
369     case kArmAdd:
370       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
371              i.OutputSBit());
372       break;
373     case kArmAnd:
374       __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
375               i.OutputSBit());
376       break;
377     case kArmBic:
378       __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
379              i.OutputSBit());
380       break;
381     case kArmMul:
382       __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
383              i.OutputSBit());
384       break;
385     case kArmMla:
386       __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
387              i.InputRegister(2), i.OutputSBit());
388       break;
389     case kArmMls: {
390       CpuFeatureScope scope(masm(), MLS);
391       __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
392              i.InputRegister(2));
393       DCHECK_EQ(LeaveCC, i.OutputSBit());
394       break;
395     }
396     case kArmSmmul:
397       __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
398       DCHECK_EQ(LeaveCC, i.OutputSBit());
399       break;
400     case kArmSmmla:
401       __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
402                i.InputRegister(2));
403       DCHECK_EQ(LeaveCC, i.OutputSBit());
404       break;
405     case kArmUmull:
406       __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
407                i.InputRegister(1), i.OutputSBit());
408       break;
409     case kArmSdiv: {
410       CpuFeatureScope scope(masm(), SUDIV);
411       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
412       DCHECK_EQ(LeaveCC, i.OutputSBit());
413       break;
414     }
415     case kArmUdiv: {
416       CpuFeatureScope scope(masm(), SUDIV);
417       __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
418       DCHECK_EQ(LeaveCC, i.OutputSBit());
419       break;
420     }
421     case kArmMov:
422       __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
423       break;
424     case kArmMvn:
425       __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
426       break;
427     case kArmOrr:
428       __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
429              i.OutputSBit());
430       break;
431     case kArmEor:
432       __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
433              i.OutputSBit());
434       break;
435     case kArmSub:
436       __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
437              i.OutputSBit());
438       break;
439     case kArmRsb:
440       __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
441              i.OutputSBit());
442       break;
443     case kArmBfc: {
444       CpuFeatureScope scope(masm(), ARMv7);
445       __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
446       DCHECK_EQ(LeaveCC, i.OutputSBit());
447       break;
448     }
449     case kArmUbfx: {
450       CpuFeatureScope scope(masm(), ARMv7);
451       __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
452               i.InputInt8(2));
453       DCHECK_EQ(LeaveCC, i.OutputSBit());
454       break;
455     }
456     case kArmSxtb:
457       __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
458       DCHECK_EQ(LeaveCC, i.OutputSBit());
459       break;
460     case kArmSxth:
461       __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
462       DCHECK_EQ(LeaveCC, i.OutputSBit());
463       break;
464     case kArmSxtab:
465       __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
466                i.InputInt32(2));
467       DCHECK_EQ(LeaveCC, i.OutputSBit());
468       break;
469     case kArmSxtah:
470       __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
471                i.InputInt32(2));
472       DCHECK_EQ(LeaveCC, i.OutputSBit());
473       break;
474     case kArmUxtb:
475       __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
476       DCHECK_EQ(LeaveCC, i.OutputSBit());
477       break;
478     case kArmUxth:
479       __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
480       DCHECK_EQ(LeaveCC, i.OutputSBit());
481       break;
482     case kArmUxtab:
483       __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
484                i.InputInt32(2));
485       DCHECK_EQ(LeaveCC, i.OutputSBit());
486       break;
487     case kArmUxtah:
488       __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
489                i.InputInt32(2));
490       DCHECK_EQ(LeaveCC, i.OutputSBit());
491       break;
492     case kArmClz:
493       __ clz(i.OutputRegister(), i.InputRegister(0));
494       DCHECK_EQ(LeaveCC, i.OutputSBit());
495       break;
496     case kArmCmp:
497       __ cmp(i.InputRegister(0), i.InputOperand2(1));
498       DCHECK_EQ(SetCC, i.OutputSBit());
499       break;
500     case kArmCmn:
501       __ cmn(i.InputRegister(0), i.InputOperand2(1));
502       DCHECK_EQ(SetCC, i.OutputSBit());
503       break;
504     case kArmTst:
505       __ tst(i.InputRegister(0), i.InputOperand2(1));
506       DCHECK_EQ(SetCC, i.OutputSBit());
507       break;
508     case kArmTeq:
509       __ teq(i.InputRegister(0), i.InputOperand2(1));
510       DCHECK_EQ(SetCC, i.OutputSBit());
511       break;
512     case kArmVcmpF64:
513       if (instr->InputAt(1)->IsDoubleRegister()) {
514         __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
515                                  i.InputFloat64Register(1));
516       } else {
517         DCHECK(instr->InputAt(1)->IsImmediate());
518         // 0.0 is the only immediate supported by vcmp instructions.
519         DCHECK(i.InputDouble(1) == 0.0);
520         __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
521       }
522       DCHECK_EQ(SetCC, i.OutputSBit());
523       break;
524     case kArmVaddF64:
525       __ vadd(i.OutputFloat64Register(), i.InputFloat64Register(0),
526               i.InputFloat64Register(1));
527       DCHECK_EQ(LeaveCC, i.OutputSBit());
528       break;
529     case kArmVsubF64:
530       __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
531               i.InputFloat64Register(1));
532       DCHECK_EQ(LeaveCC, i.OutputSBit());
533       break;
534     case kArmVmulF64:
535       __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
536               i.InputFloat64Register(1));
537       DCHECK_EQ(LeaveCC, i.OutputSBit());
538       break;
539     case kArmVmlaF64:
540       __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
541               i.InputFloat64Register(2));
542       DCHECK_EQ(LeaveCC, i.OutputSBit());
543       break;
544     case kArmVmlsF64:
545       __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
546               i.InputFloat64Register(2));
547       DCHECK_EQ(LeaveCC, i.OutputSBit());
548       break;
549     case kArmVdivF64:
550       __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
551               i.InputFloat64Register(1));
552       DCHECK_EQ(LeaveCC, i.OutputSBit());
553       break;
554     case kArmVmodF64: {
555       // TODO(bmeurer): We should really get rid of this special instruction,
556       // and generate a CallAddress instruction instead.
557       FrameScope scope(masm(), StackFrame::MANUAL);
558       __ PrepareCallCFunction(0, 2, kScratchReg);
559       __ MovToFloatParameters(i.InputFloat64Register(0),
560                               i.InputFloat64Register(1));
561       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
562                        0, 2);
563       // Move the result in the double result register.
564       __ MovFromFloatResult(i.OutputFloat64Register());
565       DCHECK_EQ(LeaveCC, i.OutputSBit());
566       break;
567     }
568     case kArmVsqrtF64:
569       __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
570       break;
571     case kArmVrintmF64:
572       __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
573       break;
574     case kArmVrintpF64:
575       __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
576       break;
577     case kArmVrintzF64:
578       __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
579       break;
580     case kArmVrintaF64:
581       __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
582       break;
583     case kArmVnegF64:
584       __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
585       break;
586     case kArmVcvtF32F64: {
587       __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
588       DCHECK_EQ(LeaveCC, i.OutputSBit());
589       break;
590     }
591     case kArmVcvtF64F32: {
592       __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
593       DCHECK_EQ(LeaveCC, i.OutputSBit());
594       break;
595     }
596     case kArmVcvtF64S32: {
597       SwVfpRegister scratch = kScratchDoubleReg.low();
598       __ vmov(scratch, i.InputRegister(0));
599       __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
600       DCHECK_EQ(LeaveCC, i.OutputSBit());
601       break;
602     }
603     case kArmVcvtF64U32: {
604       SwVfpRegister scratch = kScratchDoubleReg.low();
605       __ vmov(scratch, i.InputRegister(0));
606       __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
607       DCHECK_EQ(LeaveCC, i.OutputSBit());
608       break;
609     }
610     case kArmVcvtS32F64: {
611       SwVfpRegister scratch = kScratchDoubleReg.low();
612       __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
613       __ vmov(i.OutputRegister(), scratch);
614       DCHECK_EQ(LeaveCC, i.OutputSBit());
615       break;
616     }
617     case kArmVcvtU32F64: {
618       SwVfpRegister scratch = kScratchDoubleReg.low();
619       __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
620       __ vmov(i.OutputRegister(), scratch);
621       DCHECK_EQ(LeaveCC, i.OutputSBit());
622       break;
623     }
624     case kArmVmovLowU32F64:
625       __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
626       DCHECK_EQ(LeaveCC, i.OutputSBit());
627       break;
628     case kArmVmovLowF64U32:
629       __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
630       DCHECK_EQ(LeaveCC, i.OutputSBit());
631       break;
632     case kArmVmovHighU32F64:
633       __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
634       DCHECK_EQ(LeaveCC, i.OutputSBit());
635       break;
636     case kArmVmovHighF64U32:
637       __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
638       DCHECK_EQ(LeaveCC, i.OutputSBit());
639       break;
640     case kArmVmovF64U32U32:
641       __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
642               i.InputRegister(1));
643       DCHECK_EQ(LeaveCC, i.OutputSBit());
644       break;
645     case kArmLdrb:
646       __ ldrb(i.OutputRegister(), i.InputOffset());
647       DCHECK_EQ(LeaveCC, i.OutputSBit());
648       break;
649     case kArmLdrsb:
650       __ ldrsb(i.OutputRegister(), i.InputOffset());
651       DCHECK_EQ(LeaveCC, i.OutputSBit());
652       break;
653     case kArmStrb: {
654       size_t index = 0;
655       MemOperand operand = i.InputOffset(&index);
656       __ strb(i.InputRegister(index), operand);
657       DCHECK_EQ(LeaveCC, i.OutputSBit());
658       break;
659     }
660     case kArmLdrh:
661       __ ldrh(i.OutputRegister(), i.InputOffset());
662       break;
663     case kArmLdrsh:
664       __ ldrsh(i.OutputRegister(), i.InputOffset());
665       break;
666     case kArmStrh: {
667       size_t index = 0;
668       MemOperand operand = i.InputOffset(&index);
669       __ strh(i.InputRegister(index), operand);
670       DCHECK_EQ(LeaveCC, i.OutputSBit());
671       break;
672     }
673     case kArmLdr:
674       __ ldr(i.OutputRegister(), i.InputOffset());
675       break;
676     case kArmStr: {
677       size_t index = 0;
678       MemOperand operand = i.InputOffset(&index);
679       __ str(i.InputRegister(index), operand);
680       DCHECK_EQ(LeaveCC, i.OutputSBit());
681       break;
682     }
683     case kArmVldrF32: {
684       __ vldr(i.OutputFloat32Register(), i.InputOffset());
685       DCHECK_EQ(LeaveCC, i.OutputSBit());
686       break;
687     }
688     case kArmVstrF32: {
689       size_t index = 0;
690       MemOperand operand = i.InputOffset(&index);
691       __ vstr(i.InputFloat32Register(index), operand);
692       DCHECK_EQ(LeaveCC, i.OutputSBit());
693       break;
694     }
695     case kArmVldrF64:
696       __ vldr(i.OutputFloat64Register(), i.InputOffset());
697       DCHECK_EQ(LeaveCC, i.OutputSBit());
698       break;
699     case kArmVstrF64: {
700       size_t index = 0;
701       MemOperand operand = i.InputOffset(&index);
702       __ vstr(i.InputFloat64Register(index), operand);
703       DCHECK_EQ(LeaveCC, i.OutputSBit());
704       break;
705     }
706     case kArmPush:
707       __ Push(i.InputRegister(0));
708       DCHECK_EQ(LeaveCC, i.OutputSBit());
709       break;
710     case kArmStoreWriteBarrier: {
711       Register object = i.InputRegister(0);
712       Register index = i.InputRegister(1);
713       Register value = i.InputRegister(2);
714       __ add(index, object, index);
715       __ str(value, MemOperand(index));
716       SaveFPRegsMode mode =
717           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
718       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
719       __ RecordWrite(object, index, value, lr_status, mode);
720       DCHECK_EQ(LeaveCC, i.OutputSBit());
721       break;
722     }
723     case kCheckedLoadInt8:
724       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
725       break;
726     case kCheckedLoadUint8:
727       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
728       break;
729     case kCheckedLoadInt16:
730       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
731       break;
732     case kCheckedLoadUint16:
733       ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
734       break;
735     case kCheckedLoadWord32:
736       ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
737       break;
738     case kCheckedLoadFloat32:
739       ASSEMBLE_CHECKED_LOAD_FLOAT(32);
740       break;
741     case kCheckedLoadFloat64:
742       ASSEMBLE_CHECKED_LOAD_FLOAT(64);
743       break;
744     case kCheckedStoreWord8:
745       ASSEMBLE_CHECKED_STORE_INTEGER(strb);
746       break;
747     case kCheckedStoreWord16:
748       ASSEMBLE_CHECKED_STORE_INTEGER(strh);
749       break;
750     case kCheckedStoreWord32:
751       ASSEMBLE_CHECKED_STORE_INTEGER(str);
752       break;
753     case kCheckedStoreFloat32:
754       ASSEMBLE_CHECKED_STORE_FLOAT(32);
755       break;
756     case kCheckedStoreFloat64:
757       ASSEMBLE_CHECKED_STORE_FLOAT(64);
758       break;
759   }
760 }
761
762
763 // Assembles branches after an instruction.
764 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
765   ArmOperandConverter i(this, instr);
766   Label* tlabel = branch->true_label;
767   Label* flabel = branch->false_label;
768   Condition cc = FlagsConditionToCondition(branch->condition);
769   __ b(cc, tlabel);
770   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
771 }
772
773
774 void CodeGenerator::AssembleArchJump(RpoNumber target) {
775   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
776 }
777
778
779 // Assembles boolean materializations after an instruction.
780 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
781                                         FlagsCondition condition) {
782   ArmOperandConverter i(this, instr);
783
784   // Materialize a full 32-bit 1 or 0 value. The result register is always the
785   // last output of the instruction.
786   DCHECK_NE(0u, instr->OutputCount());
787   Register reg = i.OutputRegister(instr->OutputCount() - 1);
788   Condition cc = FlagsConditionToCondition(condition);
789   __ mov(reg, Operand(0));
790   __ mov(reg, Operand(1), LeaveCC, cc);
791 }
792
793
794 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
795   ArmOperandConverter i(this, instr);
796   Register input = i.InputRegister(0);
797   for (size_t index = 2; index < instr->InputCount(); index += 2) {
798     __ cmp(input, Operand(i.InputInt32(index + 0)));
799     __ b(eq, GetLabel(i.InputRpo(index + 1)));
800   }
801   AssembleArchJump(i.InputRpo(1));
802 }
803
804
805 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
806   ArmOperandConverter i(this, instr);
807   Register input = i.InputRegister(0);
808   size_t const case_count = instr->InputCount() - 2;
809   __ CheckConstPool(true, true);
810   __ cmp(input, Operand(case_count));
811   __ BlockConstPoolFor(case_count + 2);
812   __ ldr(pc, MemOperand(pc, input, LSL, 2), lo);
813   __ b(GetLabel(i.InputRpo(1)));
814   for (size_t index = 0; index < case_count; ++index) {
815     __ dd(GetLabel(i.InputRpo(index + 2)));
816   }
817 }
818
819
820 void CodeGenerator::AssembleDeoptimizerCall(
821     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
822   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
823       isolate(), deoptimization_id, bailout_type);
824   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
825 }
826
827
828 void CodeGenerator::AssemblePrologue() {
829   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
830   int stack_slots = frame()->GetSpillSlotCount();
831   if (descriptor->kind() == CallDescriptor::kCallAddress) {
832     bool saved_pp;
833     if (FLAG_enable_ool_constant_pool) {
834       __ Push(lr, fp, pp);
835       // Adjust FP to point to saved FP.
836       __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
837       saved_pp = true;
838     } else {
839       __ Push(lr, fp);
840       __ mov(fp, sp);
841       saved_pp = false;
842     }
843     const RegList saves = descriptor->CalleeSavedRegisters();
844     if (saves != 0 || saved_pp) {
845       // Save callee-saved registers.
846       int register_save_area_size = saved_pp ? kPointerSize : 0;
847       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
848         if (!((1 << i) & saves)) continue;
849         register_save_area_size += kPointerSize;
850       }
851       frame()->SetRegisterSaveAreaSize(register_save_area_size);
852       __ stm(db_w, sp, saves);
853     }
854   } else if (descriptor->IsJSFunctionCall()) {
855     CompilationInfo* info = this->info();
856     __ Prologue(info->IsCodePreAgingActive());
857     frame()->SetRegisterSaveAreaSize(
858         StandardFrameConstants::kFixedFrameSizeFromFp);
859   } else if (stack_slots > 0) {
860     __ StubPrologue();
861     frame()->SetRegisterSaveAreaSize(
862         StandardFrameConstants::kFixedFrameSizeFromFp);
863   }
864
865   if (info()->is_osr()) {
866     // TurboFan OSR-compiled functions cannot be entered directly.
867     __ Abort(kShouldNotDirectlyEnterOsrFunction);
868
869     // Unoptimized code jumps directly to this entrypoint while the unoptimized
870     // frame is still on the stack. Optimized code uses OSR values directly from
871     // the unoptimized frame. Thus, all that needs to be done is to allocate the
872     // remaining stack slots.
873     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
874     osr_pc_offset_ = __ pc_offset();
875     // TODO(titzer): cannot address target function == local #-1
876     __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
877     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
878     stack_slots -= frame()->GetOsrStackSlotCount();
879   }
880
881   if (stack_slots > 0) {
882     __ sub(sp, sp, Operand(stack_slots * kPointerSize));
883   }
884 }
885
886
887 void CodeGenerator::AssembleReturn() {
888   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
889   int stack_slots = frame()->GetSpillSlotCount();
890   if (descriptor->kind() == CallDescriptor::kCallAddress) {
891     if (frame()->GetRegisterSaveAreaSize() > 0) {
892       // Remove this frame's spill slots first.
893       if (stack_slots > 0) {
894         __ add(sp, sp, Operand(stack_slots * kPointerSize));
895       }
896       // Restore registers.
897       const RegList saves = descriptor->CalleeSavedRegisters();
898       if (saves != 0) {
899         __ ldm(ia_w, sp, saves);
900       }
901     }
902     __ LeaveFrame(StackFrame::MANUAL);
903     __ Ret();
904   } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
905     __ LeaveFrame(StackFrame::MANUAL);
906     int pop_count = descriptor->IsJSFunctionCall()
907                         ? static_cast<int>(descriptor->JSParameterCount())
908                         : 0;
909     __ Drop(pop_count);
910     __ Ret();
911   } else {
912     __ Ret();
913   }
914 }
915
916
917 void CodeGenerator::AssembleMove(InstructionOperand* source,
918                                  InstructionOperand* destination) {
919   ArmOperandConverter g(this, NULL);
920   // Dispatch on the source and destination operand kinds.  Not all
921   // combinations are possible.
922   if (source->IsRegister()) {
923     DCHECK(destination->IsRegister() || destination->IsStackSlot());
924     Register src = g.ToRegister(source);
925     if (destination->IsRegister()) {
926       __ mov(g.ToRegister(destination), src);
927     } else {
928       __ str(src, g.ToMemOperand(destination));
929     }
930   } else if (source->IsStackSlot()) {
931     DCHECK(destination->IsRegister() || destination->IsStackSlot());
932     MemOperand src = g.ToMemOperand(source);
933     if (destination->IsRegister()) {
934       __ ldr(g.ToRegister(destination), src);
935     } else {
936       Register temp = kScratchReg;
937       __ ldr(temp, src);
938       __ str(temp, g.ToMemOperand(destination));
939     }
940   } else if (source->IsConstant()) {
941     Constant src = g.ToConstant(source);
942     if (destination->IsRegister() || destination->IsStackSlot()) {
943       Register dst =
944           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
945       switch (src.type()) {
946         case Constant::kInt32:
947           __ mov(dst, Operand(src.ToInt32()));
948           break;
949         case Constant::kInt64:
950           UNREACHABLE();
951           break;
952         case Constant::kFloat32:
953           __ Move(dst,
954                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
955           break;
956         case Constant::kFloat64:
957           __ Move(dst,
958                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
959           break;
960         case Constant::kExternalReference:
961           __ mov(dst, Operand(src.ToExternalReference()));
962           break;
963         case Constant::kHeapObject:
964           __ Move(dst, src.ToHeapObject());
965           break;
966         case Constant::kRpoNumber:
967           UNREACHABLE();  // TODO(dcarney): loading RPO constants on arm.
968           break;
969       }
970       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
971     } else if (src.type() == Constant::kFloat32) {
972       if (destination->IsDoubleStackSlot()) {
973         MemOperand dst = g.ToMemOperand(destination);
974         __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
975         __ str(ip, dst);
976       } else {
977         SwVfpRegister dst = g.ToFloat32Register(destination);
978         __ vmov(dst, src.ToFloat32());
979       }
980     } else {
981       DCHECK_EQ(Constant::kFloat64, src.type());
982       DwVfpRegister dst = destination->IsDoubleRegister()
983                               ? g.ToFloat64Register(destination)
984                               : kScratchDoubleReg;
985       __ vmov(dst, src.ToFloat64(), kScratchReg);
986       if (destination->IsDoubleStackSlot()) {
987         __ vstr(dst, g.ToMemOperand(destination));
988       }
989     }
990   } else if (source->IsDoubleRegister()) {
991     DwVfpRegister src = g.ToDoubleRegister(source);
992     if (destination->IsDoubleRegister()) {
993       DwVfpRegister dst = g.ToDoubleRegister(destination);
994       __ Move(dst, src);
995     } else {
996       DCHECK(destination->IsDoubleStackSlot());
997       __ vstr(src, g.ToMemOperand(destination));
998     }
999   } else if (source->IsDoubleStackSlot()) {
1000     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1001     MemOperand src = g.ToMemOperand(source);
1002     if (destination->IsDoubleRegister()) {
1003       __ vldr(g.ToDoubleRegister(destination), src);
1004     } else {
1005       DwVfpRegister temp = kScratchDoubleReg;
1006       __ vldr(temp, src);
1007       __ vstr(temp, g.ToMemOperand(destination));
1008     }
1009   } else {
1010     UNREACHABLE();
1011   }
1012 }
1013
1014
1015 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1016                                  InstructionOperand* destination) {
1017   ArmOperandConverter g(this, NULL);
1018   // Dispatch on the source and destination operand kinds.  Not all
1019   // combinations are possible.
1020   if (source->IsRegister()) {
1021     // Register-register.
1022     Register temp = kScratchReg;
1023     Register src = g.ToRegister(source);
1024     if (destination->IsRegister()) {
1025       Register dst = g.ToRegister(destination);
1026       __ Move(temp, src);
1027       __ Move(src, dst);
1028       __ Move(dst, temp);
1029     } else {
1030       DCHECK(destination->IsStackSlot());
1031       MemOperand dst = g.ToMemOperand(destination);
1032       __ mov(temp, src);
1033       __ ldr(src, dst);
1034       __ str(temp, dst);
1035     }
1036   } else if (source->IsStackSlot()) {
1037     DCHECK(destination->IsStackSlot());
1038     Register temp_0 = kScratchReg;
1039     SwVfpRegister temp_1 = kScratchDoubleReg.low();
1040     MemOperand src = g.ToMemOperand(source);
1041     MemOperand dst = g.ToMemOperand(destination);
1042     __ ldr(temp_0, src);
1043     __ vldr(temp_1, dst);
1044     __ str(temp_0, dst);
1045     __ vstr(temp_1, src);
1046   } else if (source->IsDoubleRegister()) {
1047     DwVfpRegister temp = kScratchDoubleReg;
1048     DwVfpRegister src = g.ToDoubleRegister(source);
1049     if (destination->IsDoubleRegister()) {
1050       DwVfpRegister dst = g.ToDoubleRegister(destination);
1051       __ Move(temp, src);
1052       __ Move(src, dst);
1053       __ Move(dst, temp);
1054     } else {
1055       DCHECK(destination->IsDoubleStackSlot());
1056       MemOperand dst = g.ToMemOperand(destination);
1057       __ Move(temp, src);
1058       __ vldr(src, dst);
1059       __ vstr(temp, dst);
1060     }
1061   } else if (source->IsDoubleStackSlot()) {
1062     DCHECK(destination->IsDoubleStackSlot());
1063     Register temp_0 = kScratchReg;
1064     DwVfpRegister temp_1 = kScratchDoubleReg;
1065     MemOperand src0 = g.ToMemOperand(source);
1066     MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
1067     MemOperand dst0 = g.ToMemOperand(destination);
1068     MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
1069     __ vldr(temp_1, dst0);  // Save destination in temp_1.
1070     __ ldr(temp_0, src0);   // Then use temp_0 to copy source to destination.
1071     __ str(temp_0, dst0);
1072     __ ldr(temp_0, src1);
1073     __ str(temp_0, dst1);
1074     __ vstr(temp_1, src0);
1075   } else {
1076     // No other combinations are possible.
1077     UNREACHABLE();
1078   }
1079 }
1080
1081
1082 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1083   // On 32-bit ARM we emit the jump tables inline.
1084   UNREACHABLE();
1085 }
1086
1087
1088 void CodeGenerator::AddNopForSmiCodeInlining() {
1089   // On 32-bit ARM we do not insert nops for inlined Smi code.
1090 }
1091
1092
1093 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1094   int space_needed = Deoptimizer::patch_size();
1095   if (!info()->IsStub()) {
1096     // Ensure that we have enough space after the previous lazy-bailout
1097     // instruction for patching the code here.
1098     int current_pc = masm()->pc_offset();
1099     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1100       // Block literal pool emission for duration of padding.
1101       v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
1102       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1103       DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1104       while (padding_size > 0) {
1105         __ nop();
1106         padding_size -= v8::internal::Assembler::kInstrSize;
1107       }
1108     }
1109   }
1110   MarkLazyDeoptSite();
1111 }
1112
1113 #undef __
1114
1115 }  // namespace compiler
1116 }  // namespace internal
1117 }  // namespace v8