Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / 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/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 #define kScratchReg r9
22
23
24 // Adds Arm-specific methods to convert InstructionOperands.
25 class ArmOperandConverter : public InstructionOperandConverter {
26  public:
27   ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
28       : InstructionOperandConverter(gen, instr) {}
29
30   SBit OutputSBit() const {
31     switch (instr_->flags_mode()) {
32       case kFlags_branch:
33       case kFlags_set:
34         return SetCC;
35       case kFlags_none:
36         return LeaveCC;
37     }
38     UNREACHABLE();
39     return LeaveCC;
40   }
41
42   Operand InputImmediate(int index) {
43     Constant constant = ToConstant(instr_->InputAt(index));
44     switch (constant.type()) {
45       case Constant::kInt32:
46         return Operand(constant.ToInt32());
47       case Constant::kFloat64:
48         return Operand(
49             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
50       case Constant::kInt64:
51       case Constant::kExternalReference:
52       case Constant::kHeapObject:
53         break;
54     }
55     UNREACHABLE();
56     return Operand::Zero();
57   }
58
59   Operand InputOperand2(int first_index) {
60     const int index = first_index;
61     switch (AddressingModeField::decode(instr_->opcode())) {
62       case kMode_None:
63       case kMode_Offset_RI:
64       case kMode_Offset_RR:
65         break;
66       case kMode_Operand2_I:
67         return InputImmediate(index + 0);
68       case kMode_Operand2_R:
69         return Operand(InputRegister(index + 0));
70       case kMode_Operand2_R_ASR_I:
71         return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1));
72       case kMode_Operand2_R_ASR_R:
73         return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1));
74       case kMode_Operand2_R_LSL_I:
75         return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1));
76       case kMode_Operand2_R_LSL_R:
77         return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1));
78       case kMode_Operand2_R_LSR_I:
79         return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
80       case kMode_Operand2_R_LSR_R:
81         return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
82       case kMode_Operand2_R_ROR_I:
83         return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
84       case kMode_Operand2_R_ROR_R:
85         return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
86     }
87     UNREACHABLE();
88     return Operand::Zero();
89   }
90
91   MemOperand InputOffset(int* first_index) {
92     const int index = *first_index;
93     switch (AddressingModeField::decode(instr_->opcode())) {
94       case kMode_None:
95       case kMode_Operand2_I:
96       case kMode_Operand2_R:
97       case kMode_Operand2_R_ASR_I:
98       case kMode_Operand2_R_ASR_R:
99       case kMode_Operand2_R_LSL_I:
100       case kMode_Operand2_R_LSL_R:
101       case kMode_Operand2_R_LSR_I:
102       case kMode_Operand2_R_LSR_R:
103       case kMode_Operand2_R_ROR_I:
104       case kMode_Operand2_R_ROR_R:
105         break;
106       case kMode_Offset_RI:
107         *first_index += 2;
108         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
109       case kMode_Offset_RR:
110         *first_index += 2;
111         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
112     }
113     UNREACHABLE();
114     return MemOperand(r0);
115   }
116
117   MemOperand InputOffset() {
118     int index = 0;
119     return InputOffset(&index);
120   }
121
122   MemOperand ToMemOperand(InstructionOperand* op) const {
123     DCHECK(op != NULL);
124     DCHECK(!op->IsRegister());
125     DCHECK(!op->IsDoubleRegister());
126     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
127     // The linkage computes where all spill slots are located.
128     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
129     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
130   }
131 };
132
133
134 // Assembles an instruction after register allocation, producing machine code.
135 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
136   ArmOperandConverter i(this, instr);
137
138   switch (ArchOpcodeField::decode(instr->opcode())) {
139     case kArchCallCodeObject: {
140       EnsureSpaceForLazyDeopt();
141       if (instr->InputAt(0)->IsImmediate()) {
142         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
143                 RelocInfo::CODE_TARGET);
144       } else {
145         __ add(ip, i.InputRegister(0),
146                Operand(Code::kHeaderSize - kHeapObjectTag));
147         __ Call(ip);
148       }
149       AddSafepointAndDeopt(instr);
150       DCHECK_EQ(LeaveCC, i.OutputSBit());
151       break;
152     }
153     case kArchCallJSFunction: {
154       EnsureSpaceForLazyDeopt();
155       Register func = i.InputRegister(0);
156       if (FLAG_debug_code) {
157         // Check the function's context matches the context argument.
158         __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
159         __ cmp(cp, kScratchReg);
160         __ Assert(eq, kWrongFunctionContext);
161       }
162       __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
163       __ Call(ip);
164       AddSafepointAndDeopt(instr);
165       DCHECK_EQ(LeaveCC, i.OutputSBit());
166       break;
167     }
168     case kArchJmp:
169       __ b(code_->GetLabel(i.InputBlock(0)));
170       DCHECK_EQ(LeaveCC, i.OutputSBit());
171       break;
172     case kArchNop:
173       // don't emit code for nops.
174       DCHECK_EQ(LeaveCC, i.OutputSBit());
175       break;
176     case kArchRet:
177       AssembleReturn();
178       DCHECK_EQ(LeaveCC, i.OutputSBit());
179       break;
180     case kArchTruncateDoubleToI:
181       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
182       DCHECK_EQ(LeaveCC, i.OutputSBit());
183       break;
184     case kArmAdd:
185       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
186              i.OutputSBit());
187       break;
188     case kArmAnd:
189       __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
190               i.OutputSBit());
191       break;
192     case kArmBic:
193       __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
194              i.OutputSBit());
195       break;
196     case kArmMul:
197       __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
198              i.OutputSBit());
199       break;
200     case kArmMla:
201       __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
202              i.InputRegister(2), i.OutputSBit());
203       break;
204     case kArmMls: {
205       CpuFeatureScope scope(masm(), MLS);
206       __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
207              i.InputRegister(2));
208       DCHECK_EQ(LeaveCC, i.OutputSBit());
209       break;
210     }
211     case kArmSdiv: {
212       CpuFeatureScope scope(masm(), SUDIV);
213       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
214       DCHECK_EQ(LeaveCC, i.OutputSBit());
215       break;
216     }
217     case kArmUdiv: {
218       CpuFeatureScope scope(masm(), SUDIV);
219       __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
220       DCHECK_EQ(LeaveCC, i.OutputSBit());
221       break;
222     }
223     case kArmMov:
224       __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
225       break;
226     case kArmMvn:
227       __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
228       break;
229     case kArmOrr:
230       __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
231              i.OutputSBit());
232       break;
233     case kArmEor:
234       __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
235              i.OutputSBit());
236       break;
237     case kArmSub:
238       __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
239              i.OutputSBit());
240       break;
241     case kArmRsb:
242       __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
243              i.OutputSBit());
244       break;
245     case kArmBfc: {
246       CpuFeatureScope scope(masm(), ARMv7);
247       __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
248       DCHECK_EQ(LeaveCC, i.OutputSBit());
249       break;
250     }
251     case kArmUbfx: {
252       CpuFeatureScope scope(masm(), ARMv7);
253       __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
254               i.InputInt8(2));
255       DCHECK_EQ(LeaveCC, i.OutputSBit());
256       break;
257     }
258     case kArmCmp:
259       __ cmp(i.InputRegister(0), i.InputOperand2(1));
260       DCHECK_EQ(SetCC, i.OutputSBit());
261       break;
262     case kArmCmn:
263       __ cmn(i.InputRegister(0), i.InputOperand2(1));
264       DCHECK_EQ(SetCC, i.OutputSBit());
265       break;
266     case kArmTst:
267       __ tst(i.InputRegister(0), i.InputOperand2(1));
268       DCHECK_EQ(SetCC, i.OutputSBit());
269       break;
270     case kArmTeq:
271       __ teq(i.InputRegister(0), i.InputOperand2(1));
272       DCHECK_EQ(SetCC, i.OutputSBit());
273       break;
274     case kArmVcmpF64:
275       __ VFPCompareAndSetFlags(i.InputDoubleRegister(0),
276                                i.InputDoubleRegister(1));
277       DCHECK_EQ(SetCC, i.OutputSBit());
278       break;
279     case kArmVaddF64:
280       __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
281               i.InputDoubleRegister(1));
282       DCHECK_EQ(LeaveCC, i.OutputSBit());
283       break;
284     case kArmVsubF64:
285       __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
286               i.InputDoubleRegister(1));
287       DCHECK_EQ(LeaveCC, i.OutputSBit());
288       break;
289     case kArmVmulF64:
290       __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
291               i.InputDoubleRegister(1));
292       DCHECK_EQ(LeaveCC, i.OutputSBit());
293       break;
294     case kArmVmlaF64:
295       __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
296               i.InputDoubleRegister(2));
297       DCHECK_EQ(LeaveCC, i.OutputSBit());
298       break;
299     case kArmVmlsF64:
300       __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
301               i.InputDoubleRegister(2));
302       DCHECK_EQ(LeaveCC, i.OutputSBit());
303       break;
304     case kArmVdivF64:
305       __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
306               i.InputDoubleRegister(1));
307       DCHECK_EQ(LeaveCC, i.OutputSBit());
308       break;
309     case kArmVmodF64: {
310       // TODO(bmeurer): We should really get rid of this special instruction,
311       // and generate a CallAddress instruction instead.
312       FrameScope scope(masm(), StackFrame::MANUAL);
313       __ PrepareCallCFunction(0, 2, kScratchReg);
314       __ MovToFloatParameters(i.InputDoubleRegister(0),
315                               i.InputDoubleRegister(1));
316       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
317                        0, 2);
318       // Move the result in the double result register.
319       __ MovFromFloatResult(i.OutputDoubleRegister());
320       DCHECK_EQ(LeaveCC, i.OutputSBit());
321       break;
322     }
323     case kArmVnegF64:
324       __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
325       break;
326     case kArmVsqrtF64:
327       __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
328       break;
329     case kArmVcvtF64S32: {
330       SwVfpRegister scratch = kScratchDoubleReg.low();
331       __ vmov(scratch, i.InputRegister(0));
332       __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch);
333       DCHECK_EQ(LeaveCC, i.OutputSBit());
334       break;
335     }
336     case kArmVcvtF64U32: {
337       SwVfpRegister scratch = kScratchDoubleReg.low();
338       __ vmov(scratch, i.InputRegister(0));
339       __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch);
340       DCHECK_EQ(LeaveCC, i.OutputSBit());
341       break;
342     }
343     case kArmVcvtS32F64: {
344       SwVfpRegister scratch = kScratchDoubleReg.low();
345       __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0));
346       __ vmov(i.OutputRegister(), scratch);
347       DCHECK_EQ(LeaveCC, i.OutputSBit());
348       break;
349     }
350     case kArmVcvtU32F64: {
351       SwVfpRegister scratch = kScratchDoubleReg.low();
352       __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0));
353       __ vmov(i.OutputRegister(), scratch);
354       DCHECK_EQ(LeaveCC, i.OutputSBit());
355       break;
356     }
357     case kArmLdrb:
358       __ ldrb(i.OutputRegister(), i.InputOffset());
359       DCHECK_EQ(LeaveCC, i.OutputSBit());
360       break;
361     case kArmLdrsb:
362       __ ldrsb(i.OutputRegister(), i.InputOffset());
363       DCHECK_EQ(LeaveCC, i.OutputSBit());
364       break;
365     case kArmStrb: {
366       int index = 0;
367       MemOperand operand = i.InputOffset(&index);
368       __ strb(i.InputRegister(index), operand);
369       DCHECK_EQ(LeaveCC, i.OutputSBit());
370       break;
371     }
372     case kArmLdrh:
373       __ ldrh(i.OutputRegister(), i.InputOffset());
374       break;
375     case kArmLdrsh:
376       __ ldrsh(i.OutputRegister(), i.InputOffset());
377       break;
378     case kArmStrh: {
379       int index = 0;
380       MemOperand operand = i.InputOffset(&index);
381       __ strh(i.InputRegister(index), operand);
382       DCHECK_EQ(LeaveCC, i.OutputSBit());
383       break;
384     }
385     case kArmLdr:
386       __ ldr(i.OutputRegister(), i.InputOffset());
387       break;
388     case kArmStr: {
389       int index = 0;
390       MemOperand operand = i.InputOffset(&index);
391       __ str(i.InputRegister(index), operand);
392       DCHECK_EQ(LeaveCC, i.OutputSBit());
393       break;
394     }
395     case kArmVldr32: {
396       SwVfpRegister scratch = kScratchDoubleReg.low();
397       __ vldr(scratch, i.InputOffset());
398       __ vcvt_f64_f32(i.OutputDoubleRegister(), scratch);
399       DCHECK_EQ(LeaveCC, i.OutputSBit());
400       break;
401     }
402     case kArmVstr32: {
403       int index = 0;
404       SwVfpRegister scratch = kScratchDoubleReg.low();
405       MemOperand operand = i.InputOffset(&index);
406       __ vcvt_f32_f64(scratch, i.InputDoubleRegister(index));
407       __ vstr(scratch, operand);
408       DCHECK_EQ(LeaveCC, i.OutputSBit());
409       break;
410     }
411     case kArmVldr64:
412       __ vldr(i.OutputDoubleRegister(), i.InputOffset());
413       DCHECK_EQ(LeaveCC, i.OutputSBit());
414       break;
415     case kArmVstr64: {
416       int index = 0;
417       MemOperand operand = i.InputOffset(&index);
418       __ vstr(i.InputDoubleRegister(index), operand);
419       DCHECK_EQ(LeaveCC, i.OutputSBit());
420       break;
421     }
422     case kArmPush:
423       __ Push(i.InputRegister(0));
424       DCHECK_EQ(LeaveCC, i.OutputSBit());
425       break;
426     case kArmStoreWriteBarrier: {
427       Register object = i.InputRegister(0);
428       Register index = i.InputRegister(1);
429       Register value = i.InputRegister(2);
430       __ add(index, object, index);
431       __ str(value, MemOperand(index));
432       SaveFPRegsMode mode =
433           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
434       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
435       __ RecordWrite(object, index, value, lr_status, mode);
436       DCHECK_EQ(LeaveCC, i.OutputSBit());
437       break;
438     }
439   }
440 }
441
442
443 // Assembles branches after an instruction.
444 void CodeGenerator::AssembleArchBranch(Instruction* instr,
445                                        FlagsCondition condition) {
446   ArmOperandConverter i(this, instr);
447   Label done;
448
449   // Emit a branch. The true and false targets are always the last two inputs
450   // to the instruction.
451   BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
452   BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
453   bool fallthru = IsNextInAssemblyOrder(fblock);
454   Label* tlabel = code()->GetLabel(tblock);
455   Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
456   switch (condition) {
457     case kUnorderedEqual:
458       __ b(vs, flabel);
459     // Fall through.
460     case kEqual:
461       __ b(eq, tlabel);
462       break;
463     case kUnorderedNotEqual:
464       __ b(vs, tlabel);
465     // Fall through.
466     case kNotEqual:
467       __ b(ne, tlabel);
468       break;
469     case kSignedLessThan:
470       __ b(lt, tlabel);
471       break;
472     case kSignedGreaterThanOrEqual:
473       __ b(ge, tlabel);
474       break;
475     case kSignedLessThanOrEqual:
476       __ b(le, tlabel);
477       break;
478     case kSignedGreaterThan:
479       __ b(gt, tlabel);
480       break;
481     case kUnorderedLessThan:
482       __ b(vs, flabel);
483     // Fall through.
484     case kUnsignedLessThan:
485       __ b(lo, tlabel);
486       break;
487     case kUnorderedGreaterThanOrEqual:
488       __ b(vs, tlabel);
489     // Fall through.
490     case kUnsignedGreaterThanOrEqual:
491       __ b(hs, tlabel);
492       break;
493     case kUnorderedLessThanOrEqual:
494       __ b(vs, flabel);
495     // Fall through.
496     case kUnsignedLessThanOrEqual:
497       __ b(ls, tlabel);
498       break;
499     case kUnorderedGreaterThan:
500       __ b(vs, tlabel);
501     // Fall through.
502     case kUnsignedGreaterThan:
503       __ b(hi, tlabel);
504       break;
505     case kOverflow:
506       __ b(vs, tlabel);
507       break;
508     case kNotOverflow:
509       __ b(vc, tlabel);
510       break;
511   }
512   if (!fallthru) __ b(flabel);  // no fallthru to flabel.
513   __ bind(&done);
514 }
515
516
517 // Assembles boolean materializations after an instruction.
518 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
519                                         FlagsCondition condition) {
520   ArmOperandConverter i(this, instr);
521   Label done;
522
523   // Materialize a full 32-bit 1 or 0 value. The result register is always the
524   // last output of the instruction.
525   Label check;
526   DCHECK_NE(0, instr->OutputCount());
527   Register reg = i.OutputRegister(instr->OutputCount() - 1);
528   Condition cc = kNoCondition;
529   switch (condition) {
530     case kUnorderedEqual:
531       __ b(vc, &check);
532       __ mov(reg, Operand(0));
533       __ b(&done);
534     // Fall through.
535     case kEqual:
536       cc = eq;
537       break;
538     case kUnorderedNotEqual:
539       __ b(vc, &check);
540       __ mov(reg, Operand(1));
541       __ b(&done);
542     // Fall through.
543     case kNotEqual:
544       cc = ne;
545       break;
546     case kSignedLessThan:
547       cc = lt;
548       break;
549     case kSignedGreaterThanOrEqual:
550       cc = ge;
551       break;
552     case kSignedLessThanOrEqual:
553       cc = le;
554       break;
555     case kSignedGreaterThan:
556       cc = gt;
557       break;
558     case kUnorderedLessThan:
559       __ b(vc, &check);
560       __ mov(reg, Operand(0));
561       __ b(&done);
562     // Fall through.
563     case kUnsignedLessThan:
564       cc = lo;
565       break;
566     case kUnorderedGreaterThanOrEqual:
567       __ b(vc, &check);
568       __ mov(reg, Operand(1));
569       __ b(&done);
570     // Fall through.
571     case kUnsignedGreaterThanOrEqual:
572       cc = hs;
573       break;
574     case kUnorderedLessThanOrEqual:
575       __ b(vc, &check);
576       __ mov(reg, Operand(0));
577       __ b(&done);
578     // Fall through.
579     case kUnsignedLessThanOrEqual:
580       cc = ls;
581       break;
582     case kUnorderedGreaterThan:
583       __ b(vc, &check);
584       __ mov(reg, Operand(1));
585       __ b(&done);
586     // Fall through.
587     case kUnsignedGreaterThan:
588       cc = hi;
589       break;
590     case kOverflow:
591       cc = vs;
592       break;
593     case kNotOverflow:
594       cc = vc;
595       break;
596   }
597   __ bind(&check);
598   __ mov(reg, Operand(0));
599   __ mov(reg, Operand(1), LeaveCC, cc);
600   __ bind(&done);
601 }
602
603
604 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
605   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
606       isolate(), deoptimization_id, Deoptimizer::LAZY);
607   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
608 }
609
610
611 void CodeGenerator::AssemblePrologue() {
612   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
613   if (descriptor->kind() == CallDescriptor::kCallAddress) {
614     bool saved_pp;
615     if (FLAG_enable_ool_constant_pool) {
616       __ Push(lr, fp, pp);
617       // Adjust FP to point to saved FP.
618       __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
619       saved_pp = true;
620     } else {
621       __ Push(lr, fp);
622       __ mov(fp, sp);
623       saved_pp = false;
624     }
625     const RegList saves = descriptor->CalleeSavedRegisters();
626     if (saves != 0 || saved_pp) {
627       // Save callee-saved registers.
628       int register_save_area_size = saved_pp ? kPointerSize : 0;
629       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
630         if (!((1 << i) & saves)) continue;
631         register_save_area_size += kPointerSize;
632       }
633       frame()->SetRegisterSaveAreaSize(register_save_area_size);
634       __ stm(db_w, sp, saves);
635     }
636   } else if (descriptor->IsJSFunctionCall()) {
637     CompilationInfo* info = linkage()->info();
638     __ Prologue(info->IsCodePreAgingActive());
639     frame()->SetRegisterSaveAreaSize(
640         StandardFrameConstants::kFixedFrameSizeFromFp);
641
642     // Sloppy mode functions and builtins need to replace the receiver with the
643     // global proxy when called as functions (without an explicit receiver
644     // object).
645     // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
646     if (info->strict_mode() == SLOPPY && !info->is_native()) {
647       Label ok;
648       // +2 for return address and saved frame pointer.
649       int receiver_slot = info->scope()->num_parameters() + 2;
650       __ ldr(r2, MemOperand(fp, receiver_slot * kPointerSize));
651       __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
652       __ b(ne, &ok);
653       __ ldr(r2, GlobalObjectOperand());
654       __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalProxyOffset));
655       __ str(r2, MemOperand(fp, receiver_slot * kPointerSize));
656       __ bind(&ok);
657     }
658
659   } else {
660     __ StubPrologue();
661     frame()->SetRegisterSaveAreaSize(
662         StandardFrameConstants::kFixedFrameSizeFromFp);
663   }
664   int stack_slots = frame()->GetSpillSlotCount();
665   if (stack_slots > 0) {
666     __ sub(sp, sp, Operand(stack_slots * kPointerSize));
667   }
668 }
669
670
671 void CodeGenerator::AssembleReturn() {
672   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
673   if (descriptor->kind() == CallDescriptor::kCallAddress) {
674     if (frame()->GetRegisterSaveAreaSize() > 0) {
675       // Remove this frame's spill slots first.
676       int stack_slots = frame()->GetSpillSlotCount();
677       if (stack_slots > 0) {
678         __ add(sp, sp, Operand(stack_slots * kPointerSize));
679       }
680       // Restore registers.
681       const RegList saves = descriptor->CalleeSavedRegisters();
682       if (saves != 0) {
683         __ ldm(ia_w, sp, saves);
684       }
685     }
686     __ LeaveFrame(StackFrame::MANUAL);
687     __ Ret();
688   } else {
689     __ LeaveFrame(StackFrame::MANUAL);
690     int pop_count = descriptor->IsJSFunctionCall()
691                         ? static_cast<int>(descriptor->JSParameterCount())
692                         : 0;
693     __ Drop(pop_count);
694     __ Ret();
695   }
696 }
697
698
699 void CodeGenerator::AssembleMove(InstructionOperand* source,
700                                  InstructionOperand* destination) {
701   ArmOperandConverter g(this, NULL);
702   // Dispatch on the source and destination operand kinds.  Not all
703   // combinations are possible.
704   if (source->IsRegister()) {
705     DCHECK(destination->IsRegister() || destination->IsStackSlot());
706     Register src = g.ToRegister(source);
707     if (destination->IsRegister()) {
708       __ mov(g.ToRegister(destination), src);
709     } else {
710       __ str(src, g.ToMemOperand(destination));
711     }
712   } else if (source->IsStackSlot()) {
713     DCHECK(destination->IsRegister() || destination->IsStackSlot());
714     MemOperand src = g.ToMemOperand(source);
715     if (destination->IsRegister()) {
716       __ ldr(g.ToRegister(destination), src);
717     } else {
718       Register temp = kScratchReg;
719       __ ldr(temp, src);
720       __ str(temp, g.ToMemOperand(destination));
721     }
722   } else if (source->IsConstant()) {
723     if (destination->IsRegister() || destination->IsStackSlot()) {
724       Register dst =
725           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
726       Constant src = g.ToConstant(source);
727       switch (src.type()) {
728         case Constant::kInt32:
729           __ mov(dst, Operand(src.ToInt32()));
730           break;
731         case Constant::kInt64:
732           UNREACHABLE();
733           break;
734         case Constant::kFloat64:
735           __ Move(dst,
736                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
737           break;
738         case Constant::kExternalReference:
739           __ mov(dst, Operand(src.ToExternalReference()));
740           break;
741         case Constant::kHeapObject:
742           __ Move(dst, src.ToHeapObject());
743           break;
744       }
745       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
746     } else if (destination->IsDoubleRegister()) {
747       DwVfpRegister result = g.ToDoubleRegister(destination);
748       __ vmov(result, g.ToDouble(source));
749     } else {
750       DCHECK(destination->IsDoubleStackSlot());
751       DwVfpRegister temp = kScratchDoubleReg;
752       __ vmov(temp, g.ToDouble(source));
753       __ vstr(temp, g.ToMemOperand(destination));
754     }
755   } else if (source->IsDoubleRegister()) {
756     DwVfpRegister src = g.ToDoubleRegister(source);
757     if (destination->IsDoubleRegister()) {
758       DwVfpRegister dst = g.ToDoubleRegister(destination);
759       __ Move(dst, src);
760     } else {
761       DCHECK(destination->IsDoubleStackSlot());
762       __ vstr(src, g.ToMemOperand(destination));
763     }
764   } else if (source->IsDoubleStackSlot()) {
765     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
766     MemOperand src = g.ToMemOperand(source);
767     if (destination->IsDoubleRegister()) {
768       __ vldr(g.ToDoubleRegister(destination), src);
769     } else {
770       DwVfpRegister temp = kScratchDoubleReg;
771       __ vldr(temp, src);
772       __ vstr(temp, g.ToMemOperand(destination));
773     }
774   } else {
775     UNREACHABLE();
776   }
777 }
778
779
780 void CodeGenerator::AssembleSwap(InstructionOperand* source,
781                                  InstructionOperand* destination) {
782   ArmOperandConverter g(this, NULL);
783   // Dispatch on the source and destination operand kinds.  Not all
784   // combinations are possible.
785   if (source->IsRegister()) {
786     // Register-register.
787     Register temp = kScratchReg;
788     Register src = g.ToRegister(source);
789     if (destination->IsRegister()) {
790       Register dst = g.ToRegister(destination);
791       __ Move(temp, src);
792       __ Move(src, dst);
793       __ Move(dst, temp);
794     } else {
795       DCHECK(destination->IsStackSlot());
796       MemOperand dst = g.ToMemOperand(destination);
797       __ mov(temp, src);
798       __ ldr(src, dst);
799       __ str(temp, dst);
800     }
801   } else if (source->IsStackSlot()) {
802     DCHECK(destination->IsStackSlot());
803     Register temp_0 = kScratchReg;
804     SwVfpRegister temp_1 = kScratchDoubleReg.low();
805     MemOperand src = g.ToMemOperand(source);
806     MemOperand dst = g.ToMemOperand(destination);
807     __ ldr(temp_0, src);
808     __ vldr(temp_1, dst);
809     __ str(temp_0, dst);
810     __ vstr(temp_1, src);
811   } else if (source->IsDoubleRegister()) {
812     DwVfpRegister temp = kScratchDoubleReg;
813     DwVfpRegister src = g.ToDoubleRegister(source);
814     if (destination->IsDoubleRegister()) {
815       DwVfpRegister dst = g.ToDoubleRegister(destination);
816       __ Move(temp, src);
817       __ Move(src, dst);
818       __ Move(dst, temp);
819     } else {
820       DCHECK(destination->IsDoubleStackSlot());
821       MemOperand dst = g.ToMemOperand(destination);
822       __ Move(temp, src);
823       __ vldr(src, dst);
824       __ vstr(temp, dst);
825     }
826   } else if (source->IsDoubleStackSlot()) {
827     DCHECK(destination->IsDoubleStackSlot());
828     Register temp_0 = kScratchReg;
829     DwVfpRegister temp_1 = kScratchDoubleReg;
830     MemOperand src0 = g.ToMemOperand(source);
831     MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
832     MemOperand dst0 = g.ToMemOperand(destination);
833     MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
834     __ vldr(temp_1, dst0);  // Save destination in temp_1.
835     __ ldr(temp_0, src0);   // Then use temp_0 to copy source to destination.
836     __ str(temp_0, dst0);
837     __ ldr(temp_0, src1);
838     __ str(temp_0, dst1);
839     __ vstr(temp_1, src0);
840   } else {
841     // No other combinations are possible.
842     UNREACHABLE();
843   }
844 }
845
846
847 void CodeGenerator::AddNopForSmiCodeInlining() {
848   // On 32-bit ARM we do not insert nops for inlined Smi code.
849 }
850
851
852 void CodeGenerator::EnsureSpaceForLazyDeopt() {
853   int space_needed = Deoptimizer::patch_size();
854   if (!linkage()->info()->IsStub()) {
855     // Ensure that we have enough space after the previous lazy-bailout
856     // instruction for patching the code here.
857     int current_pc = masm()->pc_offset();
858     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
859       // Block literal pool emission for duration of padding.
860       v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
861       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
862       DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
863       while (padding_size > 0) {
864         __ nop();
865         padding_size -= v8::internal::Assembler::kInstrSize;
866       }
867     }
868   }
869   MarkLazyDeoptSite();
870 }
871
872 #undef __
873
874 }  // namespace compiler
875 }  // namespace internal
876 }  // namespace v8