blob: a0b502237b047fa9b14abc682ef87514d752e366 [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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/ast/scopes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/compiler/code-generator-impl.h"
10#include "src/compiler/gap-resolver.h"
11#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/compiler/osr.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013
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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025class ArmOperandConverter final : public InstructionOperandConverter {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026 public:
27 ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
28 : InstructionOperandConverter(gen, instr) {}
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 SwVfpRegister OutputFloat32Register(size_t index = 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031 return ToFloat32Register(instr_->OutputAt(index));
32 }
33
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 SwVfpRegister InputFloat32Register(size_t index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040035 return ToFloat32Register(instr_->InputAt(index));
36 }
37
38 SwVfpRegister ToFloat32Register(InstructionOperand* op) {
39 return ToFloat64Register(op).low();
40 }
41
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 LowDwVfpRegister OutputFloat64Register(size_t index = 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040043 return ToFloat64Register(instr_->OutputAt(index));
44 }
45
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 LowDwVfpRegister InputFloat64Register(size_t index) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047 return ToFloat64Register(instr_->InputAt(index));
48 }
49
50 LowDwVfpRegister ToFloat64Register(InstructionOperand* op) {
51 return LowDwVfpRegister::from_code(ToDoubleRegister(op).code());
52 }
53
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 SBit OutputSBit() const {
55 switch (instr_->flags_mode()) {
56 case kFlags_branch:
Ben Murdochda12d292016-06-02 14:46:10 +010057 case kFlags_deoptimize:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058 case kFlags_set:
59 return SetCC;
60 case kFlags_none:
61 return LeaveCC;
62 }
63 UNREACHABLE();
64 return LeaveCC;
65 }
66
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 Operand InputImmediate(size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 Constant constant = ToConstant(instr_->InputAt(index));
69 switch (constant.type()) {
70 case Constant::kInt32:
71 return Operand(constant.ToInt32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040072 case Constant::kFloat32:
73 return Operand(
74 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 case Constant::kFloat64:
76 return Operand(
77 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
78 case Constant::kInt64:
79 case Constant::kExternalReference:
80 case Constant::kHeapObject:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040081 case Constant::kRpoNumber:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 break;
83 }
84 UNREACHABLE();
85 return Operand::Zero();
86 }
87
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 Operand InputOperand2(size_t first_index) {
89 const size_t index = first_index;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 switch (AddressingModeField::decode(instr_->opcode())) {
91 case kMode_None:
92 case kMode_Offset_RI:
93 case kMode_Offset_RR:
94 break;
95 case kMode_Operand2_I:
96 return InputImmediate(index + 0);
97 case kMode_Operand2_R:
98 return Operand(InputRegister(index + 0));
99 case kMode_Operand2_R_ASR_I:
100 return Operand(InputRegister(index + 0), ASR, InputInt5(index + 1));
101 case kMode_Operand2_R_ASR_R:
102 return Operand(InputRegister(index + 0), ASR, InputRegister(index + 1));
103 case kMode_Operand2_R_LSL_I:
104 return Operand(InputRegister(index + 0), LSL, InputInt5(index + 1));
105 case kMode_Operand2_R_LSL_R:
106 return Operand(InputRegister(index + 0), LSL, InputRegister(index + 1));
107 case kMode_Operand2_R_LSR_I:
108 return Operand(InputRegister(index + 0), LSR, InputInt5(index + 1));
109 case kMode_Operand2_R_LSR_R:
110 return Operand(InputRegister(index + 0), LSR, InputRegister(index + 1));
111 case kMode_Operand2_R_ROR_I:
112 return Operand(InputRegister(index + 0), ROR, InputInt5(index + 1));
113 case kMode_Operand2_R_ROR_R:
114 return Operand(InputRegister(index + 0), ROR, InputRegister(index + 1));
115 }
116 UNREACHABLE();
117 return Operand::Zero();
118 }
119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 MemOperand InputOffset(size_t* first_index) {
121 const size_t index = *first_index;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 switch (AddressingModeField::decode(instr_->opcode())) {
123 case kMode_None:
124 case kMode_Operand2_I:
125 case kMode_Operand2_R:
126 case kMode_Operand2_R_ASR_I:
127 case kMode_Operand2_R_ASR_R:
128 case kMode_Operand2_R_LSL_I:
129 case kMode_Operand2_R_LSL_R:
130 case kMode_Operand2_R_LSR_I:
131 case kMode_Operand2_R_LSR_R:
132 case kMode_Operand2_R_ROR_I:
133 case kMode_Operand2_R_ROR_R:
134 break;
135 case kMode_Offset_RI:
136 *first_index += 2;
137 return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
138 case kMode_Offset_RR:
139 *first_index += 2;
140 return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
141 }
142 UNREACHABLE();
143 return MemOperand(r0);
144 }
145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 MemOperand InputOffset(size_t first_index = 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400147 return InputOffset(&first_index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 }
149
150 MemOperand ToMemOperand(InstructionOperand* op) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 DCHECK_NOT_NULL(op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
Ben Murdochda12d292016-06-02 14:46:10 +0100153 return SlotToMemOperand(AllocatedOperand::cast(op)->index());
154 }
155
156 MemOperand SlotToMemOperand(int slot) const {
157 FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
159 }
160};
161
162
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400163namespace {
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165class OutOfLineLoadFloat32 final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400166 public:
167 OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
168 : OutOfLineCode(gen), result_(result) {}
169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 void Generate() final {
Ben Murdochda12d292016-06-02 14:46:10 +0100171 // Compute sqrtf(-1.0f), which results in a quiet single-precision NaN.
172 __ vmov(result_, -1.0f);
173 __ vsqrt(result_, result_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400174 }
175
176 private:
177 SwVfpRegister const result_;
178};
179
180
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181class OutOfLineLoadFloat64 final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182 public:
183 OutOfLineLoadFloat64(CodeGenerator* gen, DwVfpRegister result)
184 : OutOfLineCode(gen), result_(result) {}
185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 void Generate() final {
Ben Murdochda12d292016-06-02 14:46:10 +0100187 // Compute sqrt(-1.0), which results in a quiet double-precision NaN.
188 __ vmov(result_, -1.0);
189 __ vsqrt(result_, result_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 }
191
192 private:
193 DwVfpRegister const result_;
194};
195
196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400198 public:
199 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
200 : OutOfLineCode(gen), result_(result) {}
201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 void Generate() final { __ mov(result_, Operand::Zero()); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203
204 private:
205 Register const result_;
206};
207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208
209class OutOfLineRecordWrite final : public OutOfLineCode {
210 public:
211 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
212 Register value, Register scratch0, Register scratch1,
213 RecordWriteMode mode)
214 : OutOfLineCode(gen),
215 object_(object),
216 index_(index),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100217 index_immediate_(0),
218 value_(value),
219 scratch0_(scratch0),
220 scratch1_(scratch1),
221 mode_(mode) {}
222
223 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
224 Register value, Register scratch0, Register scratch1,
225 RecordWriteMode mode)
226 : OutOfLineCode(gen),
227 object_(object),
228 index_(no_reg),
229 index_immediate_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 value_(value),
231 scratch0_(scratch0),
232 scratch1_(scratch1),
Ben Murdochda12d292016-06-02 14:46:10 +0100233 mode_(mode),
234 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235
236 void Generate() final {
237 if (mode_ > RecordWriteMode::kValueIsPointer) {
238 __ JumpIfSmi(value_, exit());
239 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100240 __ CheckPageFlag(value_, scratch0_,
241 MemoryChunk::kPointersToHereAreInterestingMask, eq,
242 exit());
243 RememberedSetAction const remembered_set_action =
244 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
245 : OMIT_REMEMBERED_SET;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 SaveFPRegsMode const save_fp_mode =
247 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
Ben Murdochda12d292016-06-02 14:46:10 +0100248 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100249 // We need to save and restore lr if the frame was elided.
250 __ Push(lr);
251 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100253 remembered_set_action, save_fp_mode);
254 if (index_.is(no_reg)) {
255 __ add(scratch1_, object_, Operand(index_immediate_));
256 } else {
257 DCHECK_EQ(0, index_immediate_);
258 __ add(scratch1_, object_, Operand(index_));
259 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 __ CallStub(&stub);
Ben Murdochda12d292016-06-02 14:46:10 +0100261 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 __ Pop(lr);
263 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 }
265
266 private:
267 Register const object_;
268 Register const index_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100269 int32_t const index_immediate_; // Valid if index_.is(no_reg).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 Register const value_;
271 Register const scratch0_;
272 Register const scratch1_;
273 RecordWriteMode const mode_;
Ben Murdochda12d292016-06-02 14:46:10 +0100274 bool must_save_lr_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275};
276
277
278Condition FlagsConditionToCondition(FlagsCondition condition) {
279 switch (condition) {
280 case kEqual:
281 return eq;
282 case kNotEqual:
283 return ne;
284 case kSignedLessThan:
285 return lt;
286 case kSignedGreaterThanOrEqual:
287 return ge;
288 case kSignedLessThanOrEqual:
289 return le;
290 case kSignedGreaterThan:
291 return gt;
292 case kUnsignedLessThan:
293 return lo;
294 case kUnsignedGreaterThanOrEqual:
295 return hs;
296 case kUnsignedLessThanOrEqual:
297 return ls;
298 case kUnsignedGreaterThan:
299 return hi;
300 case kFloatLessThanOrUnordered:
301 return lt;
302 case kFloatGreaterThanOrEqual:
303 return ge;
304 case kFloatLessThanOrEqual:
305 return ls;
306 case kFloatGreaterThanOrUnordered:
307 return hi;
308 case kFloatLessThan:
309 return lo;
310 case kFloatGreaterThanOrEqualOrUnordered:
311 return hs;
312 case kFloatLessThanOrEqualOrUnordered:
313 return le;
314 case kFloatGreaterThan:
315 return gt;
316 case kOverflow:
317 return vs;
318 case kNotOverflow:
319 return vc;
320 default:
321 break;
322 }
323 UNREACHABLE();
324 return kNoCondition;
325}
326
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400327} // namespace
328
329
330#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \
331 do { \
332 auto result = i.OutputFloat##width##Register(); \
333 auto offset = i.InputRegister(0); \
334 if (instr->InputAt(1)->IsRegister()) { \
335 __ cmp(offset, i.InputRegister(1)); \
336 } else { \
337 __ cmp(offset, i.InputImmediate(1)); \
338 } \
339 auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \
340 __ b(hs, ool->entry()); \
341 __ vldr(result, i.InputOffset(2)); \
342 __ bind(ool->exit()); \
343 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
344 } while (0)
345
346
347#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
348 do { \
349 auto result = i.OutputRegister(); \
350 auto offset = i.InputRegister(0); \
351 if (instr->InputAt(1)->IsRegister()) { \
352 __ cmp(offset, i.InputRegister(1)); \
353 } else { \
354 __ cmp(offset, i.InputImmediate(1)); \
355 } \
356 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
357 __ b(hs, ool->entry()); \
358 __ asm_instr(result, i.InputOffset(2)); \
359 __ bind(ool->exit()); \
360 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
361 } while (0)
362
363
364#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \
365 do { \
366 auto offset = i.InputRegister(0); \
367 if (instr->InputAt(1)->IsRegister()) { \
368 __ cmp(offset, i.InputRegister(1)); \
369 } else { \
370 __ cmp(offset, i.InputImmediate(1)); \
371 } \
372 auto value = i.InputFloat##width##Register(2); \
373 __ vstr(value, i.InputOffset(3), lo); \
374 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
375 } while (0)
376
377
378#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
379 do { \
380 auto offset = i.InputRegister(0); \
381 if (instr->InputAt(1)->IsRegister()) { \
382 __ cmp(offset, i.InputRegister(1)); \
383 } else { \
384 __ cmp(offset, i.InputImmediate(1)); \
385 } \
386 auto value = i.InputRegister(2); \
387 __ asm_instr(value, i.InputOffset(3), lo); \
388 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
389 } while (0)
390
Ben Murdochda12d292016-06-02 14:46:10 +0100391void CodeGenerator::AssembleDeconstructFrame() {
392 __ LeaveFrame(StackFrame::MANUAL);
393}
394
395void CodeGenerator::AssembleSetupStackPointer() {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
398 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
399 if (sp_slot_delta > 0) {
400 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
401 }
402 frame_access_state()->SetFrameAccessToDefault();
403}
404
405
406void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
407 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
408 if (sp_slot_delta < 0) {
409 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
410 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
411 }
Ben Murdochda12d292016-06-02 14:46:10 +0100412 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 if (FLAG_enable_embedded_constant_pool) {
414 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
415 }
416 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
417 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
418 }
419 frame_access_state()->SetFrameAccessToSP();
420}
421
Ben Murdochda12d292016-06-02 14:46:10 +0100422void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
423 Register scratch1,
424 Register scratch2,
425 Register scratch3) {
426 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
427 Label done;
428
429 // Check if current frame is an arguments adaptor frame.
430 __ ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
431 __ cmp(scratch1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
432 __ b(ne, &done);
433
434 // Load arguments count from current arguments adaptor frame (note, it
435 // does not include receiver).
436 Register caller_args_count_reg = scratch1;
437 __ ldr(caller_args_count_reg,
438 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
439 __ SmiUntag(caller_args_count_reg);
440
441 ParameterCount callee_args_count(args_reg);
442 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
443 scratch3);
444 __ bind(&done);
445}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447// Assembles an instruction after register allocation, producing machine code.
448void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
449 ArmOperandConverter i(this, instr);
450
Ben Murdochda12d292016-06-02 14:46:10 +0100451 __ MaybeCheckConstPool();
452 InstructionCode opcode = instr->opcode();
453 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
454 switch (arch_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000455 case kArchCallCodeObject: {
456 EnsureSpaceForLazyDeopt();
457 if (instr->InputAt(0)->IsImmediate()) {
458 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
459 RelocInfo::CODE_TARGET);
460 } else {
461 __ add(ip, i.InputRegister(0),
462 Operand(Code::kHeaderSize - kHeapObjectTag));
463 __ Call(ip);
464 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 RecordCallPosition(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 DCHECK_EQ(LeaveCC, i.OutputSBit());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 frame_access_state()->ClearSPDelta();
468 break;
469 }
Ben Murdochda12d292016-06-02 14:46:10 +0100470 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 case kArchTailCallCodeObject: {
472 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
473 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100474 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
475 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
476 i.TempRegister(0), i.TempRegister(1),
477 i.TempRegister(2));
478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 if (instr->InputAt(0)->IsImmediate()) {
480 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
481 RelocInfo::CODE_TARGET);
482 } else {
483 __ add(ip, i.InputRegister(0),
484 Operand(Code::kHeaderSize - kHeapObjectTag));
485 __ Jump(ip);
486 }
487 DCHECK_EQ(LeaveCC, i.OutputSBit());
488 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 break;
490 }
491 case kArchCallJSFunction: {
492 EnsureSpaceForLazyDeopt();
493 Register func = i.InputRegister(0);
494 if (FLAG_debug_code) {
495 // Check the function's context matches the context argument.
496 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
497 __ cmp(cp, kScratchReg);
498 __ Assert(eq, kWrongFunctionContext);
499 }
500 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
501 __ Call(ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502 RecordCallPosition(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 DCHECK_EQ(LeaveCC, i.OutputSBit());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504 frame_access_state()->ClearSPDelta();
505 break;
506 }
Ben Murdochda12d292016-06-02 14:46:10 +0100507 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508 case kArchTailCallJSFunction: {
509 Register func = i.InputRegister(0);
510 if (FLAG_debug_code) {
511 // Check the function's context matches the context argument.
512 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
513 __ cmp(cp, kScratchReg);
514 __ Assert(eq, kWrongFunctionContext);
515 }
516 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
517 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100518 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
519 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
520 i.TempRegister(0), i.TempRegister(1),
521 i.TempRegister(2));
522 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
524 __ Jump(ip);
525 DCHECK_EQ(LeaveCC, i.OutputSBit());
526 frame_access_state()->ClearSPDelta();
527 break;
528 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529 case kArchPrepareCallCFunction: {
530 int const num_parameters = MiscField::decode(instr->opcode());
531 __ PrepareCallCFunction(num_parameters, kScratchReg);
532 // Frame alignment requires using FP-relative frame addressing.
533 frame_access_state()->SetFrameAccessToFP();
534 break;
535 }
536 case kArchPrepareTailCall:
537 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
538 break;
539 case kArchCallCFunction: {
540 int const num_parameters = MiscField::decode(instr->opcode());
541 if (instr->InputAt(0)->IsImmediate()) {
542 ExternalReference ref = i.InputExternalReference(0);
543 __ CallCFunction(ref, num_parameters);
544 } else {
545 Register func = i.InputRegister(0);
546 __ CallCFunction(func, num_parameters);
547 }
548 frame_access_state()->SetFrameAccessToDefault();
549 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 break;
551 }
552 case kArchJmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400553 AssembleArchJump(i.InputRpo(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 DCHECK_EQ(LeaveCC, i.OutputSBit());
555 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 case kArchLookupSwitch:
557 AssembleArchLookupSwitch(instr);
558 DCHECK_EQ(LeaveCC, i.OutputSBit());
559 break;
560 case kArchTableSwitch:
561 AssembleArchTableSwitch(instr);
562 DCHECK_EQ(LeaveCC, i.OutputSBit());
563 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 case kArchThrowTerminator:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 // don't emit code for nops.
567 DCHECK_EQ(LeaveCC, i.OutputSBit());
568 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 case kArchDeoptimize: {
570 int deopt_state_id =
571 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
572 Deoptimizer::BailoutType bailout_type =
573 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
574 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
575 break;
576 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 case kArchRet:
578 AssembleReturn();
579 DCHECK_EQ(LeaveCC, i.OutputSBit());
580 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400581 case kArchStackPointer:
582 __ mov(i.OutputRegister(), sp);
583 DCHECK_EQ(LeaveCC, i.OutputSBit());
584 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 case kArchFramePointer:
586 __ mov(i.OutputRegister(), fp);
587 DCHECK_EQ(LeaveCC, i.OutputSBit());
588 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100589 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100590 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100591 __ ldr(i.OutputRegister(), MemOperand(fp, 0));
592 } else {
593 __ mov(i.OutputRegister(), fp);
594 }
595 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 case kArchTruncateDoubleToI:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400597 __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 DCHECK_EQ(LeaveCC, i.OutputSBit());
599 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 case kArchStoreWithWriteBarrier: {
601 RecordWriteMode mode =
602 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
603 Register object = i.InputRegister(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 Register value = i.InputRegister(2);
605 Register scratch0 = i.TempRegister(0);
606 Register scratch1 = i.TempRegister(1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100607 OutOfLineRecordWrite* ool;
608
609 AddressingMode addressing_mode =
610 AddressingModeField::decode(instr->opcode());
611 if (addressing_mode == kMode_Offset_RI) {
612 int32_t index = i.InputInt32(1);
613 ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
614 scratch0, scratch1, mode);
615 __ str(value, MemOperand(object, index));
616 } else {
617 DCHECK_EQ(kMode_Offset_RR, addressing_mode);
618 Register index(i.InputRegister(1));
619 ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
620 scratch0, scratch1, mode);
621 __ str(value, MemOperand(object, index));
622 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 __ CheckPageFlag(object, scratch0,
624 MemoryChunk::kPointersFromHereAreInterestingMask, ne,
625 ool->entry());
626 __ bind(ool->exit());
627 break;
628 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100629 case kArchStackSlot: {
630 FrameOffset offset =
631 frame_access_state()->GetFrameOffset(i.InputInt32(0));
632 Register base;
633 if (offset.from_stack_pointer()) {
634 base = sp;
635 } else {
636 base = fp;
637 }
638 __ add(i.OutputRegister(0), base, Operand(offset.offset()));
639 break;
640 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 case kArmAdd:
642 __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
643 i.OutputSBit());
644 break;
645 case kArmAnd:
646 __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
647 i.OutputSBit());
648 break;
649 case kArmBic:
650 __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
651 i.OutputSBit());
652 break;
653 case kArmMul:
654 __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
655 i.OutputSBit());
656 break;
657 case kArmMla:
658 __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
659 i.InputRegister(2), i.OutputSBit());
660 break;
661 case kArmMls: {
662 CpuFeatureScope scope(masm(), MLS);
663 __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
664 i.InputRegister(2));
665 DCHECK_EQ(LeaveCC, i.OutputSBit());
666 break;
667 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400668 case kArmSmmul:
669 __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
670 DCHECK_EQ(LeaveCC, i.OutputSBit());
671 break;
672 case kArmSmmla:
673 __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
674 i.InputRegister(2));
675 DCHECK_EQ(LeaveCC, i.OutputSBit());
676 break;
677 case kArmUmull:
678 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
679 i.InputRegister(1), i.OutputSBit());
680 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 case kArmSdiv: {
682 CpuFeatureScope scope(masm(), SUDIV);
683 __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
684 DCHECK_EQ(LeaveCC, i.OutputSBit());
685 break;
686 }
687 case kArmUdiv: {
688 CpuFeatureScope scope(masm(), SUDIV);
689 __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
690 DCHECK_EQ(LeaveCC, i.OutputSBit());
691 break;
692 }
693 case kArmMov:
694 __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
695 break;
696 case kArmMvn:
697 __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
698 break;
699 case kArmOrr:
700 __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
701 i.OutputSBit());
702 break;
703 case kArmEor:
704 __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
705 i.OutputSBit());
706 break;
707 case kArmSub:
708 __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
709 i.OutputSBit());
710 break;
711 case kArmRsb:
712 __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
713 i.OutputSBit());
714 break;
715 case kArmBfc: {
716 CpuFeatureScope scope(masm(), ARMv7);
717 __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
718 DCHECK_EQ(LeaveCC, i.OutputSBit());
719 break;
720 }
721 case kArmUbfx: {
722 CpuFeatureScope scope(masm(), ARMv7);
723 __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
724 i.InputInt8(2));
725 DCHECK_EQ(LeaveCC, i.OutputSBit());
726 break;
727 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100728 case kArmSbfx: {
729 CpuFeatureScope scope(masm(), ARMv7);
730 __ sbfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
731 i.InputInt8(2));
732 DCHECK_EQ(LeaveCC, i.OutputSBit());
733 break;
734 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735 case kArmSxtb:
736 __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
737 DCHECK_EQ(LeaveCC, i.OutputSBit());
738 break;
739 case kArmSxth:
740 __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
741 DCHECK_EQ(LeaveCC, i.OutputSBit());
742 break;
743 case kArmSxtab:
744 __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
745 i.InputInt32(2));
746 DCHECK_EQ(LeaveCC, i.OutputSBit());
747 break;
748 case kArmSxtah:
749 __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
750 i.InputInt32(2));
751 DCHECK_EQ(LeaveCC, i.OutputSBit());
752 break;
753 case kArmUxtb:
754 __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
755 DCHECK_EQ(LeaveCC, i.OutputSBit());
756 break;
757 case kArmUxth:
758 __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
759 DCHECK_EQ(LeaveCC, i.OutputSBit());
760 break;
761 case kArmUxtab:
762 __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
763 i.InputInt32(2));
764 DCHECK_EQ(LeaveCC, i.OutputSBit());
765 break;
766 case kArmUxtah:
767 __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
768 i.InputInt32(2));
769 DCHECK_EQ(LeaveCC, i.OutputSBit());
770 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100771 case kArmRbit: {
772 CpuFeatureScope scope(masm(), ARMv7);
773 __ rbit(i.OutputRegister(), i.InputRegister(0));
774 DCHECK_EQ(LeaveCC, i.OutputSBit());
775 break;
776 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000777 case kArmClz:
778 __ clz(i.OutputRegister(), i.InputRegister(0));
779 DCHECK_EQ(LeaveCC, i.OutputSBit());
780 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781 case kArmCmp:
782 __ cmp(i.InputRegister(0), i.InputOperand2(1));
783 DCHECK_EQ(SetCC, i.OutputSBit());
784 break;
785 case kArmCmn:
786 __ cmn(i.InputRegister(0), i.InputOperand2(1));
787 DCHECK_EQ(SetCC, i.OutputSBit());
788 break;
789 case kArmTst:
790 __ tst(i.InputRegister(0), i.InputOperand2(1));
791 DCHECK_EQ(SetCC, i.OutputSBit());
792 break;
793 case kArmTeq:
794 __ teq(i.InputRegister(0), i.InputOperand2(1));
795 DCHECK_EQ(SetCC, i.OutputSBit());
796 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100797 case kArmAddPair:
798 // i.InputRegister(0) ... left low word.
799 // i.InputRegister(1) ... left high word.
800 // i.InputRegister(2) ... right low word.
801 // i.InputRegister(3) ... right high word.
802 __ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
803 SBit::SetCC);
804 __ adc(i.OutputRegister(1), i.InputRegister(1),
805 Operand(i.InputRegister(3)));
806 DCHECK_EQ(LeaveCC, i.OutputSBit());
807 break;
808 case kArmSubPair:
809 // i.InputRegister(0) ... left low word.
810 // i.InputRegister(1) ... left high word.
811 // i.InputRegister(2) ... right low word.
812 // i.InputRegister(3) ... right high word.
813 __ sub(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
814 SBit::SetCC);
815 __ sbc(i.OutputRegister(1), i.InputRegister(1),
816 Operand(i.InputRegister(3)));
817 DCHECK_EQ(LeaveCC, i.OutputSBit());
818 break;
819 case kArmMulPair:
820 // i.InputRegister(0) ... left low word.
821 // i.InputRegister(1) ... left high word.
822 // i.InputRegister(2) ... right low word.
823 // i.InputRegister(3) ... right high word.
824 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
825 i.InputRegister(2));
826 __ mla(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(3),
827 i.OutputRegister(1));
828 __ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1),
829 i.OutputRegister(1));
830 break;
831 case kArmLslPair:
832 if (instr->InputAt(2)->IsImmediate()) {
833 __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
834 i.InputRegister(1), i.InputInt32(2));
835 } else {
836 __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
837 i.InputRegister(1), kScratchReg, i.InputRegister(2));
838 }
839 break;
840 case kArmLsrPair:
841 if (instr->InputAt(2)->IsImmediate()) {
842 __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
843 i.InputRegister(1), i.InputInt32(2));
844 } else {
845 __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
846 i.InputRegister(1), kScratchReg, i.InputRegister(2));
847 }
848 break;
849 case kArmAsrPair:
850 if (instr->InputAt(2)->IsImmediate()) {
851 __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
852 i.InputRegister(1), i.InputInt32(2));
853 } else {
854 __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
855 i.InputRegister(1), kScratchReg, i.InputRegister(2));
856 }
857 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000858 case kArmVcmpF32:
859 if (instr->InputAt(1)->IsDoubleRegister()) {
860 __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
861 i.InputFloat32Register(1));
862 } else {
863 DCHECK(instr->InputAt(1)->IsImmediate());
864 // 0.0 is the only immediate supported by vcmp instructions.
865 DCHECK(i.InputFloat32(1) == 0.0f);
866 __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputFloat32(1));
867 }
868 DCHECK_EQ(SetCC, i.OutputSBit());
869 break;
870 case kArmVaddF32:
871 __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
872 i.InputFloat32Register(1));
873 DCHECK_EQ(LeaveCC, i.OutputSBit());
874 break;
875 case kArmVsubF32:
876 __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
877 i.InputFloat32Register(1));
878 DCHECK_EQ(LeaveCC, i.OutputSBit());
879 break;
880 case kArmVmulF32:
881 __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
882 i.InputFloat32Register(1));
883 DCHECK_EQ(LeaveCC, i.OutputSBit());
884 break;
885 case kArmVmlaF32:
886 __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
887 i.InputFloat32Register(2));
888 DCHECK_EQ(LeaveCC, i.OutputSBit());
889 break;
890 case kArmVmlsF32:
891 __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
892 i.InputFloat32Register(2));
893 DCHECK_EQ(LeaveCC, i.OutputSBit());
894 break;
895 case kArmVdivF32:
896 __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
897 i.InputFloat32Register(1));
898 DCHECK_EQ(LeaveCC, i.OutputSBit());
899 break;
900 case kArmVsqrtF32:
901 __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
902 break;
903 case kArmVabsF32:
904 __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
905 break;
906 case kArmVnegF32:
907 __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
908 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000909 case kArmVcmpF64:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 if (instr->InputAt(1)->IsDoubleRegister()) {
911 __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
912 i.InputFloat64Register(1));
913 } else {
914 DCHECK(instr->InputAt(1)->IsImmediate());
915 // 0.0 is the only immediate supported by vcmp instructions.
916 DCHECK(i.InputDouble(1) == 0.0);
917 __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
918 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000919 DCHECK_EQ(SetCC, i.OutputSBit());
920 break;
921 case kArmVaddF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400922 __ vadd(i.OutputFloat64Register(), i.InputFloat64Register(0),
923 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000924 DCHECK_EQ(LeaveCC, i.OutputSBit());
925 break;
926 case kArmVsubF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400927 __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
928 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000929 DCHECK_EQ(LeaveCC, i.OutputSBit());
930 break;
931 case kArmVmulF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400932 __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
933 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 DCHECK_EQ(LeaveCC, i.OutputSBit());
935 break;
936 case kArmVmlaF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400937 __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
938 i.InputFloat64Register(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000939 DCHECK_EQ(LeaveCC, i.OutputSBit());
940 break;
941 case kArmVmlsF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400942 __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
943 i.InputFloat64Register(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 DCHECK_EQ(LeaveCC, i.OutputSBit());
945 break;
946 case kArmVdivF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400947 __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
948 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949 DCHECK_EQ(LeaveCC, i.OutputSBit());
950 break;
951 case kArmVmodF64: {
952 // TODO(bmeurer): We should really get rid of this special instruction,
953 // and generate a CallAddress instruction instead.
954 FrameScope scope(masm(), StackFrame::MANUAL);
955 __ PrepareCallCFunction(0, 2, kScratchReg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400956 __ MovToFloatParameters(i.InputFloat64Register(0),
957 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
959 0, 2);
960 // Move the result in the double result register.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400961 __ MovFromFloatResult(i.OutputFloat64Register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962 DCHECK_EQ(LeaveCC, i.OutputSBit());
963 break;
964 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000965 case kArmVsqrtF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400966 __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000967 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000968 case kArmVabsF64:
969 __ vabs(i.OutputFloat64Register(), i.InputFloat64Register(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400970 break;
971 case kArmVnegF64:
972 __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
973 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000974 case kArmVrintmF32:
975 __ vrintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
976 break;
977 case kArmVrintmF64:
978 __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
979 break;
980 case kArmVrintpF32:
981 __ vrintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
982 break;
983 case kArmVrintpF64:
984 __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
985 break;
986 case kArmVrintzF32:
987 __ vrintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
988 break;
989 case kArmVrintzF64:
990 __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
991 break;
992 case kArmVrintaF64:
993 __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
994 break;
995 case kArmVrintnF32:
996 __ vrintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
997 break;
998 case kArmVrintnF64:
999 __ vrintn(i.OutputFloat64Register(), i.InputFloat64Register(0));
1000 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001001 case kArmVcvtF32F64: {
1002 __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
1003 DCHECK_EQ(LeaveCC, i.OutputSBit());
1004 break;
1005 }
1006 case kArmVcvtF64F32: {
1007 __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
1008 DCHECK_EQ(LeaveCC, i.OutputSBit());
1009 break;
1010 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001011 case kArmVcvtF32S32: {
1012 SwVfpRegister scratch = kScratchDoubleReg.low();
1013 __ vmov(scratch, i.InputRegister(0));
1014 __ vcvt_f32_s32(i.OutputFloat32Register(), scratch);
1015 DCHECK_EQ(LeaveCC, i.OutputSBit());
1016 break;
1017 }
1018 case kArmVcvtF32U32: {
1019 SwVfpRegister scratch = kScratchDoubleReg.low();
1020 __ vmov(scratch, i.InputRegister(0));
1021 __ vcvt_f32_u32(i.OutputFloat32Register(), scratch);
1022 DCHECK_EQ(LeaveCC, i.OutputSBit());
1023 break;
1024 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025 case kArmVcvtF64S32: {
1026 SwVfpRegister scratch = kScratchDoubleReg.low();
1027 __ vmov(scratch, i.InputRegister(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001028 __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001029 DCHECK_EQ(LeaveCC, i.OutputSBit());
1030 break;
1031 }
1032 case kArmVcvtF64U32: {
1033 SwVfpRegister scratch = kScratchDoubleReg.low();
1034 __ vmov(scratch, i.InputRegister(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001035 __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 DCHECK_EQ(LeaveCC, i.OutputSBit());
1037 break;
1038 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001039 case kArmVcvtS32F32: {
1040 SwVfpRegister scratch = kScratchDoubleReg.low();
1041 __ vcvt_s32_f32(scratch, i.InputFloat32Register(0));
1042 __ vmov(i.OutputRegister(), scratch);
1043 DCHECK_EQ(LeaveCC, i.OutputSBit());
1044 break;
1045 }
1046 case kArmVcvtU32F32: {
1047 SwVfpRegister scratch = kScratchDoubleReg.low();
1048 __ vcvt_u32_f32(scratch, i.InputFloat32Register(0));
1049 __ vmov(i.OutputRegister(), scratch);
1050 DCHECK_EQ(LeaveCC, i.OutputSBit());
1051 break;
1052 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001053 case kArmVcvtS32F64: {
1054 SwVfpRegister scratch = kScratchDoubleReg.low();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001055 __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 __ vmov(i.OutputRegister(), scratch);
1057 DCHECK_EQ(LeaveCC, i.OutputSBit());
1058 break;
1059 }
1060 case kArmVcvtU32F64: {
1061 SwVfpRegister scratch = kScratchDoubleReg.low();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001062 __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 __ vmov(i.OutputRegister(), scratch);
1064 DCHECK_EQ(LeaveCC, i.OutputSBit());
1065 break;
1066 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 case kArmVmovLowU32F64:
1068 __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
1069 DCHECK_EQ(LeaveCC, i.OutputSBit());
1070 break;
1071 case kArmVmovLowF64U32:
1072 __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
1073 DCHECK_EQ(LeaveCC, i.OutputSBit());
1074 break;
1075 case kArmVmovHighU32F64:
1076 __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
1077 DCHECK_EQ(LeaveCC, i.OutputSBit());
1078 break;
1079 case kArmVmovHighF64U32:
1080 __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
1081 DCHECK_EQ(LeaveCC, i.OutputSBit());
1082 break;
1083 case kArmVmovF64U32U32:
1084 __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
1085 i.InputRegister(1));
1086 DCHECK_EQ(LeaveCC, i.OutputSBit());
1087 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001088 case kArmLdrb:
1089 __ ldrb(i.OutputRegister(), i.InputOffset());
1090 DCHECK_EQ(LeaveCC, i.OutputSBit());
1091 break;
1092 case kArmLdrsb:
1093 __ ldrsb(i.OutputRegister(), i.InputOffset());
1094 DCHECK_EQ(LeaveCC, i.OutputSBit());
1095 break;
1096 case kArmStrb: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001097 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001098 MemOperand operand = i.InputOffset(&index);
1099 __ strb(i.InputRegister(index), operand);
1100 DCHECK_EQ(LeaveCC, i.OutputSBit());
1101 break;
1102 }
1103 case kArmLdrh:
1104 __ ldrh(i.OutputRegister(), i.InputOffset());
1105 break;
1106 case kArmLdrsh:
1107 __ ldrsh(i.OutputRegister(), i.InputOffset());
1108 break;
1109 case kArmStrh: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001111 MemOperand operand = i.InputOffset(&index);
1112 __ strh(i.InputRegister(index), operand);
1113 DCHECK_EQ(LeaveCC, i.OutputSBit());
1114 break;
1115 }
1116 case kArmLdr:
1117 __ ldr(i.OutputRegister(), i.InputOffset());
1118 break;
1119 case kArmStr: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 MemOperand operand = i.InputOffset(&index);
1122 __ str(i.InputRegister(index), operand);
1123 DCHECK_EQ(LeaveCC, i.OutputSBit());
1124 break;
1125 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001126 case kArmVldrF32: {
1127 __ vldr(i.OutputFloat32Register(), i.InputOffset());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001128 DCHECK_EQ(LeaveCC, i.OutputSBit());
1129 break;
1130 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001131 case kArmVstrF32: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001132 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133 MemOperand operand = i.InputOffset(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001134 __ vstr(i.InputFloat32Register(index), operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001135 DCHECK_EQ(LeaveCC, i.OutputSBit());
1136 break;
1137 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001138 case kArmVldrF64:
1139 __ vldr(i.OutputFloat64Register(), i.InputOffset());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 DCHECK_EQ(LeaveCC, i.OutputSBit());
1141 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001142 case kArmVstrF64: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001144 MemOperand operand = i.InputOffset(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001145 __ vstr(i.InputFloat64Register(index), operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 DCHECK_EQ(LeaveCC, i.OutputSBit());
1147 break;
1148 }
1149 case kArmPush:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001150 if (instr->InputAt(0)->IsDoubleRegister()) {
1151 __ vpush(i.InputDoubleRegister(0));
1152 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1153 } else {
1154 __ push(i.InputRegister(0));
1155 frame_access_state()->IncreaseSPDelta(1);
1156 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157 DCHECK_EQ(LeaveCC, i.OutputSBit());
1158 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 case kArmPoke: {
1160 int const slot = MiscField::decode(instr->opcode());
1161 __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 DCHECK_EQ(LeaveCC, i.OutputSBit());
1163 break;
1164 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001165 case kCheckedLoadInt8:
1166 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
1167 break;
1168 case kCheckedLoadUint8:
1169 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
1170 break;
1171 case kCheckedLoadInt16:
1172 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
1173 break;
1174 case kCheckedLoadUint16:
1175 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
1176 break;
1177 case kCheckedLoadWord32:
1178 ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
1179 break;
1180 case kCheckedLoadFloat32:
1181 ASSEMBLE_CHECKED_LOAD_FLOAT(32);
1182 break;
1183 case kCheckedLoadFloat64:
1184 ASSEMBLE_CHECKED_LOAD_FLOAT(64);
1185 break;
1186 case kCheckedStoreWord8:
1187 ASSEMBLE_CHECKED_STORE_INTEGER(strb);
1188 break;
1189 case kCheckedStoreWord16:
1190 ASSEMBLE_CHECKED_STORE_INTEGER(strh);
1191 break;
1192 case kCheckedStoreWord32:
1193 ASSEMBLE_CHECKED_STORE_INTEGER(str);
1194 break;
1195 case kCheckedStoreFloat32:
1196 ASSEMBLE_CHECKED_STORE_FLOAT(32);
1197 break;
1198 case kCheckedStoreFloat64:
1199 ASSEMBLE_CHECKED_STORE_FLOAT(64);
1200 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201 case kCheckedLoadWord64:
1202 case kCheckedStoreWord64:
1203 UNREACHABLE(); // currently unsupported checked int64 load/store.
1204 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001205 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206} // NOLINT(readability/fn_size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001207
1208
1209// Assembles branches after an instruction.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001210void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 ArmOperandConverter i(this, instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001212 Label* tlabel = branch->true_label;
1213 Label* flabel = branch->false_label;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 Condition cc = FlagsConditionToCondition(branch->condition);
1215 __ b(cc, tlabel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001216 if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
1217}
1218
1219
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001221 if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222}
1223
1224
1225// Assembles boolean materializations after an instruction.
1226void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1227 FlagsCondition condition) {
1228 ArmOperandConverter i(this, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229
1230 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1231 // last output of the instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 DCHECK_NE(0u, instr->OutputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001233 Register reg = i.OutputRegister(instr->OutputCount() - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 Condition cc = FlagsConditionToCondition(condition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 __ mov(reg, Operand(0));
1236 __ mov(reg, Operand(1), LeaveCC, cc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001237}
1238
1239
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1241 ArmOperandConverter i(this, instr);
1242 Register input = i.InputRegister(0);
1243 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1244 __ cmp(input, Operand(i.InputInt32(index + 0)));
1245 __ b(eq, GetLabel(i.InputRpo(index + 1)));
1246 }
1247 AssembleArchJump(i.InputRpo(1));
1248}
1249
1250
1251void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1252 ArmOperandConverter i(this, instr);
1253 Register input = i.InputRegister(0);
1254 size_t const case_count = instr->InputCount() - 2;
1255 // Ensure to emit the constant pool first if necessary.
1256 __ CheckConstPool(true, true);
1257 __ cmp(input, Operand(case_count));
1258 __ BlockConstPoolFor(case_count + 2);
1259 __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo);
1260 __ b(GetLabel(i.InputRpo(1)));
1261 for (size_t index = 0; index < case_count; ++index) {
1262 __ b(GetLabel(i.InputRpo(index + 2)));
1263 }
1264}
1265
1266
1267void CodeGenerator::AssembleDeoptimizerCall(
1268 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 isolate(), deoptimization_id, bailout_type);
Ben Murdochda12d292016-06-02 14:46:10 +01001271 // TODO(turbofan): We should be able to generate better code by sharing the
1272 // actual final call site and just bl'ing to it here, similar to what we do
1273 // in the lithium backend.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochda12d292016-06-02 14:46:10 +01001275 __ CheckConstPool(false, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276}
1277
1278
1279void CodeGenerator::AssemblePrologue() {
1280 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01001281 if (frame_access_state()->has_frame()) {
1282 if (descriptor->IsCFunctionCall()) {
1283 if (FLAG_enable_embedded_constant_pool) {
1284 __ Push(lr, fp, pp);
1285 // Adjust FP to point to saved FP.
1286 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
1287 } else {
1288 __ Push(lr, fp);
1289 __ mov(fp, sp);
1290 }
1291 } else if (descriptor->IsJSFunctionCall()) {
1292 __ Prologue(this->info()->GeneratePreagedPrologue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001293 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001294 __ StubPrologue(info()->GetOutputStackFrameType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001297
1298 int stack_shrink_slots = frame()->GetSpillSlotCount();
1299 if (info()->is_osr()) {
1300 // TurboFan OSR-compiled functions cannot be entered directly.
1301 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1302
1303 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1304 // frame is still on the stack. Optimized code uses OSR values directly from
1305 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1306 // remaining stack slots.
1307 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1308 osr_pc_offset_ = __ pc_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
1310 }
1311
1312 const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
1313 if (saves_fp != 0) {
1314 stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots();
1315 }
1316 if (stack_shrink_slots > 0) {
1317 __ sub(sp, sp, Operand(stack_shrink_slots * kPointerSize));
1318 }
1319
1320 if (saves_fp != 0) {
1321 // Save callee-saved FP registers.
1322 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
1323 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
1324 uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
1325 DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
1326 __ vstm(db_w, sp, DwVfpRegister::from_code(first),
1327 DwVfpRegister::from_code(last));
1328 frame()->AllocateSavedCalleeRegisterSlots((last - first + 1) *
1329 (kDoubleSize / kPointerSize));
1330 }
1331 const RegList saves = FLAG_enable_embedded_constant_pool
1332 ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
1333 : descriptor->CalleeSavedRegisters();
1334 if (saves != 0) {
1335 // Save callee-saved registers.
1336 __ stm(db_w, sp, saves);
1337 frame()->AllocateSavedCalleeRegisterSlots(
1338 base::bits::CountPopulation32(saves));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 }
1340}
1341
1342
1343void CodeGenerator::AssembleReturn() {
1344 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 int pop_count = static_cast<int>(descriptor->StackParameterCount());
1346
1347 // Restore registers.
1348 const RegList saves = FLAG_enable_embedded_constant_pool
1349 ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
1350 : descriptor->CalleeSavedRegisters();
1351 if (saves != 0) {
1352 __ ldm(ia_w, sp, saves);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001354
1355 // Restore FP registers.
1356 const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
1357 if (saves_fp != 0) {
1358 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
1359 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
1360 uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
1361 __ vldm(ia_w, sp, DwVfpRegister::from_code(first),
1362 DwVfpRegister::from_code(last));
1363 }
1364
1365 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001366 AssembleDeconstructFrame();
1367 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001368 // Canonicalize JSFunction return sites for now.
1369 if (return_label_.is_bound()) {
1370 __ b(&return_label_);
1371 return;
1372 } else {
1373 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01001374 AssembleDeconstructFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 }
1376 }
1377 __ Ret(pop_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378}
1379
1380
1381void CodeGenerator::AssembleMove(InstructionOperand* source,
1382 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 ArmOperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001384 // Dispatch on the source and destination operand kinds. Not all
1385 // combinations are possible.
1386 if (source->IsRegister()) {
1387 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1388 Register src = g.ToRegister(source);
1389 if (destination->IsRegister()) {
1390 __ mov(g.ToRegister(destination), src);
1391 } else {
1392 __ str(src, g.ToMemOperand(destination));
1393 }
1394 } else if (source->IsStackSlot()) {
1395 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1396 MemOperand src = g.ToMemOperand(source);
1397 if (destination->IsRegister()) {
1398 __ ldr(g.ToRegister(destination), src);
1399 } else {
1400 Register temp = kScratchReg;
1401 __ ldr(temp, src);
1402 __ str(temp, g.ToMemOperand(destination));
1403 }
1404 } else if (source->IsConstant()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001405 Constant src = g.ToConstant(source);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 if (destination->IsRegister() || destination->IsStackSlot()) {
1407 Register dst =
1408 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 switch (src.type()) {
1410 case Constant::kInt32:
1411 __ mov(dst, Operand(src.ToInt32()));
1412 break;
1413 case Constant::kInt64:
1414 UNREACHABLE();
1415 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001416 case Constant::kFloat32:
1417 __ Move(dst,
1418 isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1419 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 case Constant::kFloat64:
1421 __ Move(dst,
1422 isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1423 break;
1424 case Constant::kExternalReference:
1425 __ mov(dst, Operand(src.ToExternalReference()));
1426 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 case Constant::kHeapObject: {
1428 Handle<HeapObject> src_object = src.ToHeapObject();
1429 Heap::RootListIndex index;
Ben Murdochda12d292016-06-02 14:46:10 +01001430 int slot;
1431 if (IsMaterializableFromFrame(src_object, &slot)) {
1432 __ ldr(dst, g.SlotToMemOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001433 } else if (IsMaterializableFromRoot(src_object, &index)) {
1434 __ LoadRoot(dst, index);
1435 } else {
1436 __ Move(dst, src_object);
1437 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001438 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001440 case Constant::kRpoNumber:
1441 UNREACHABLE(); // TODO(dcarney): loading RPO constants on arm.
1442 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 }
1444 if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001445 } else if (src.type() == Constant::kFloat32) {
1446 if (destination->IsDoubleStackSlot()) {
1447 MemOperand dst = g.ToMemOperand(destination);
1448 __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
1449 __ str(ip, dst);
1450 } else {
1451 SwVfpRegister dst = g.ToFloat32Register(destination);
1452 __ vmov(dst, src.ToFloat32());
1453 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001455 DCHECK_EQ(Constant::kFloat64, src.type());
1456 DwVfpRegister dst = destination->IsDoubleRegister()
1457 ? g.ToFloat64Register(destination)
1458 : kScratchDoubleReg;
1459 __ vmov(dst, src.ToFloat64(), kScratchReg);
1460 if (destination->IsDoubleStackSlot()) {
1461 __ vstr(dst, g.ToMemOperand(destination));
1462 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 }
1464 } else if (source->IsDoubleRegister()) {
1465 DwVfpRegister src = g.ToDoubleRegister(source);
1466 if (destination->IsDoubleRegister()) {
1467 DwVfpRegister dst = g.ToDoubleRegister(destination);
1468 __ Move(dst, src);
1469 } else {
1470 DCHECK(destination->IsDoubleStackSlot());
1471 __ vstr(src, g.ToMemOperand(destination));
1472 }
1473 } else if (source->IsDoubleStackSlot()) {
1474 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1475 MemOperand src = g.ToMemOperand(source);
1476 if (destination->IsDoubleRegister()) {
1477 __ vldr(g.ToDoubleRegister(destination), src);
1478 } else {
1479 DwVfpRegister temp = kScratchDoubleReg;
1480 __ vldr(temp, src);
1481 __ vstr(temp, g.ToMemOperand(destination));
1482 }
1483 } else {
1484 UNREACHABLE();
1485 }
1486}
1487
1488
1489void CodeGenerator::AssembleSwap(InstructionOperand* source,
1490 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 ArmOperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001492 // Dispatch on the source and destination operand kinds. Not all
1493 // combinations are possible.
1494 if (source->IsRegister()) {
1495 // Register-register.
1496 Register temp = kScratchReg;
1497 Register src = g.ToRegister(source);
1498 if (destination->IsRegister()) {
1499 Register dst = g.ToRegister(destination);
1500 __ Move(temp, src);
1501 __ Move(src, dst);
1502 __ Move(dst, temp);
1503 } else {
1504 DCHECK(destination->IsStackSlot());
1505 MemOperand dst = g.ToMemOperand(destination);
1506 __ mov(temp, src);
1507 __ ldr(src, dst);
1508 __ str(temp, dst);
1509 }
1510 } else if (source->IsStackSlot()) {
1511 DCHECK(destination->IsStackSlot());
1512 Register temp_0 = kScratchReg;
1513 SwVfpRegister temp_1 = kScratchDoubleReg.low();
1514 MemOperand src = g.ToMemOperand(source);
1515 MemOperand dst = g.ToMemOperand(destination);
1516 __ ldr(temp_0, src);
1517 __ vldr(temp_1, dst);
1518 __ str(temp_0, dst);
1519 __ vstr(temp_1, src);
1520 } else if (source->IsDoubleRegister()) {
1521 DwVfpRegister temp = kScratchDoubleReg;
1522 DwVfpRegister src = g.ToDoubleRegister(source);
1523 if (destination->IsDoubleRegister()) {
1524 DwVfpRegister dst = g.ToDoubleRegister(destination);
1525 __ Move(temp, src);
1526 __ Move(src, dst);
1527 __ Move(dst, temp);
1528 } else {
1529 DCHECK(destination->IsDoubleStackSlot());
1530 MemOperand dst = g.ToMemOperand(destination);
1531 __ Move(temp, src);
1532 __ vldr(src, dst);
1533 __ vstr(temp, dst);
1534 }
1535 } else if (source->IsDoubleStackSlot()) {
1536 DCHECK(destination->IsDoubleStackSlot());
1537 Register temp_0 = kScratchReg;
1538 DwVfpRegister temp_1 = kScratchDoubleReg;
1539 MemOperand src0 = g.ToMemOperand(source);
1540 MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
1541 MemOperand dst0 = g.ToMemOperand(destination);
1542 MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
1543 __ vldr(temp_1, dst0); // Save destination in temp_1.
1544 __ ldr(temp_0, src0); // Then use temp_0 to copy source to destination.
1545 __ str(temp_0, dst0);
1546 __ ldr(temp_0, src1);
1547 __ str(temp_0, dst1);
1548 __ vstr(temp_1, src0);
1549 } else {
1550 // No other combinations are possible.
1551 UNREACHABLE();
1552 }
1553}
1554
1555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1557 // On 32-bit ARM we emit the jump tables inline.
1558 UNREACHABLE();
1559}
1560
1561
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001562void CodeGenerator::AddNopForSmiCodeInlining() {
1563 // On 32-bit ARM we do not insert nops for inlined Smi code.
1564}
1565
1566
1567void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001568 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1569 return;
1570 }
1571
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 int space_needed = Deoptimizer::patch_size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001573 // Ensure that we have enough space after the previous lazy-bailout
1574 // instruction for patching the code here.
1575 int current_pc = masm()->pc_offset();
1576 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1577 // Block literal pool emission for duration of padding.
1578 v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
1579 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1580 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1581 while (padding_size > 0) {
1582 __ nop();
1583 padding_size -= v8::internal::Assembler::kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 }
1585 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001586}
1587
1588#undef __
1589
1590} // namespace compiler
1591} // namespace internal
1592} // namespace v8