blob: 1ec174d7917e34dcc91e436808f21ead4949dbae [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18#define __ masm()->
19
20
21#define kScratchReg r9
22
23
24// Adds Arm-specific methods to convert InstructionOperands.
25class 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.
135void 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.
444void 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.
518void 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
604void 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
611void 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
671void 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
699void 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
780void 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
847void CodeGenerator::AddNopForSmiCodeInlining() {
848 // On 32-bit ARM we do not insert nops for inlined Smi code.
849}
850
851
852void 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