blob: 2c9415e68d4379b613bde5a99d6b3559d8e9dd7a [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 Murdochc5610432016-08-08 18:44:38 +0100152 DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
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),
Ben Murdochc5610432016-08-08 18:44:38 +0100221 mode_(mode),
222 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223
224 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
225 Register value, Register scratch0, Register scratch1,
226 RecordWriteMode mode)
227 : OutOfLineCode(gen),
228 object_(object),
229 index_(no_reg),
230 index_immediate_(index),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 value_(value),
232 scratch0_(scratch0),
233 scratch1_(scratch1),
Ben Murdochda12d292016-06-02 14:46:10 +0100234 mode_(mode),
235 must_save_lr_(!gen->frame_access_state()->has_frame()) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236
237 void Generate() final {
238 if (mode_ > RecordWriteMode::kValueIsPointer) {
239 __ JumpIfSmi(value_, exit());
240 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 __ CheckPageFlag(value_, scratch0_,
242 MemoryChunk::kPointersToHereAreInterestingMask, eq,
243 exit());
244 RememberedSetAction const remembered_set_action =
245 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
246 : OMIT_REMEMBERED_SET;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 SaveFPRegsMode const save_fp_mode =
248 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
Ben Murdochda12d292016-06-02 14:46:10 +0100249 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100250 // We need to save and restore lr if the frame was elided.
251 __ Push(lr);
252 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100254 remembered_set_action, save_fp_mode);
255 if (index_.is(no_reg)) {
256 __ add(scratch1_, object_, Operand(index_immediate_));
257 } else {
258 DCHECK_EQ(0, index_immediate_);
259 __ add(scratch1_, object_, Operand(index_));
260 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 __ CallStub(&stub);
Ben Murdochda12d292016-06-02 14:46:10 +0100262 if (must_save_lr_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 __ Pop(lr);
264 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 }
266
267 private:
268 Register const object_;
269 Register const index_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100270 int32_t const index_immediate_; // Valid if index_.is(no_reg).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 Register const value_;
272 Register const scratch0_;
273 Register const scratch1_;
274 RecordWriteMode const mode_;
Ben Murdochda12d292016-06-02 14:46:10 +0100275 bool must_save_lr_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276};
277
278
279Condition FlagsConditionToCondition(FlagsCondition condition) {
280 switch (condition) {
281 case kEqual:
282 return eq;
283 case kNotEqual:
284 return ne;
285 case kSignedLessThan:
286 return lt;
287 case kSignedGreaterThanOrEqual:
288 return ge;
289 case kSignedLessThanOrEqual:
290 return le;
291 case kSignedGreaterThan:
292 return gt;
293 case kUnsignedLessThan:
294 return lo;
295 case kUnsignedGreaterThanOrEqual:
296 return hs;
297 case kUnsignedLessThanOrEqual:
298 return ls;
299 case kUnsignedGreaterThan:
300 return hi;
301 case kFloatLessThanOrUnordered:
302 return lt;
303 case kFloatGreaterThanOrEqual:
304 return ge;
305 case kFloatLessThanOrEqual:
306 return ls;
307 case kFloatGreaterThanOrUnordered:
308 return hi;
309 case kFloatLessThan:
310 return lo;
311 case kFloatGreaterThanOrEqualOrUnordered:
312 return hs;
313 case kFloatLessThanOrEqualOrUnordered:
314 return le;
315 case kFloatGreaterThan:
316 return gt;
317 case kOverflow:
318 return vs;
319 case kNotOverflow:
320 return vc;
321 default:
322 break;
323 }
324 UNREACHABLE();
325 return kNoCondition;
326}
327
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400328} // namespace
329
330
331#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \
332 do { \
333 auto result = i.OutputFloat##width##Register(); \
334 auto offset = i.InputRegister(0); \
335 if (instr->InputAt(1)->IsRegister()) { \
336 __ cmp(offset, i.InputRegister(1)); \
337 } else { \
338 __ cmp(offset, i.InputImmediate(1)); \
339 } \
340 auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \
341 __ b(hs, ool->entry()); \
342 __ vldr(result, i.InputOffset(2)); \
343 __ bind(ool->exit()); \
344 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
345 } while (0)
346
347
348#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
349 do { \
350 auto result = i.OutputRegister(); \
351 auto offset = i.InputRegister(0); \
352 if (instr->InputAt(1)->IsRegister()) { \
353 __ cmp(offset, i.InputRegister(1)); \
354 } else { \
355 __ cmp(offset, i.InputImmediate(1)); \
356 } \
357 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
358 __ b(hs, ool->entry()); \
359 __ asm_instr(result, i.InputOffset(2)); \
360 __ bind(ool->exit()); \
361 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
362 } while (0)
363
364
365#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \
366 do { \
367 auto offset = i.InputRegister(0); \
368 if (instr->InputAt(1)->IsRegister()) { \
369 __ cmp(offset, i.InputRegister(1)); \
370 } else { \
371 __ cmp(offset, i.InputImmediate(1)); \
372 } \
373 auto value = i.InputFloat##width##Register(2); \
374 __ vstr(value, i.InputOffset(3), lo); \
375 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
376 } while (0)
377
378
379#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
380 do { \
381 auto offset = i.InputRegister(0); \
382 if (instr->InputAt(1)->IsRegister()) { \
383 __ cmp(offset, i.InputRegister(1)); \
384 } else { \
385 __ cmp(offset, i.InputImmediate(1)); \
386 } \
387 auto value = i.InputRegister(2); \
388 __ asm_instr(value, i.InputOffset(3), lo); \
389 DCHECK_EQ(LeaveCC, i.OutputSBit()); \
390 } while (0)
391
Ben Murdochc5610432016-08-08 18:44:38 +0100392#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \
393 do { \
394 __ asm_instr(i.OutputRegister(), \
395 MemOperand(i.InputRegister(0), i.InputRegister(1))); \
396 __ dmb(ISH); \
397 } while (0)
398
399#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \
400 do { \
401 __ dmb(ISH); \
402 __ asm_instr(i.InputRegister(2), \
403 MemOperand(i.InputRegister(0), i.InputRegister(1))); \
404 __ dmb(ISH); \
405 } while (0)
406
Ben Murdochda12d292016-06-02 14:46:10 +0100407void CodeGenerator::AssembleDeconstructFrame() {
408 __ LeaveFrame(StackFrame::MANUAL);
409}
410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
412 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
413 if (sp_slot_delta > 0) {
414 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
415 }
416 frame_access_state()->SetFrameAccessToDefault();
417}
418
419
420void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
421 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
422 if (sp_slot_delta < 0) {
423 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
424 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
425 }
Ben Murdochda12d292016-06-02 14:46:10 +0100426 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 if (FLAG_enable_embedded_constant_pool) {
428 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
429 }
430 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
431 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
432 }
433 frame_access_state()->SetFrameAccessToSP();
434}
435
Ben Murdochda12d292016-06-02 14:46:10 +0100436void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
437 Register scratch1,
438 Register scratch2,
439 Register scratch3) {
440 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
441 Label done;
442
443 // Check if current frame is an arguments adaptor frame.
444 __ ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
445 __ cmp(scratch1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
446 __ b(ne, &done);
447
448 // Load arguments count from current arguments adaptor frame (note, it
449 // does not include receiver).
450 Register caller_args_count_reg = scratch1;
451 __ ldr(caller_args_count_reg,
452 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
453 __ SmiUntag(caller_args_count_reg);
454
455 ParameterCount callee_args_count(args_reg);
456 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
457 scratch3);
458 __ bind(&done);
459}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461// Assembles an instruction after register allocation, producing machine code.
Ben Murdochc5610432016-08-08 18:44:38 +0100462CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
463 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 ArmOperandConverter i(this, instr);
465
Ben Murdochda12d292016-06-02 14:46:10 +0100466 __ MaybeCheckConstPool();
467 InstructionCode opcode = instr->opcode();
468 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
469 switch (arch_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 case kArchCallCodeObject: {
471 EnsureSpaceForLazyDeopt();
472 if (instr->InputAt(0)->IsImmediate()) {
473 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
474 RelocInfo::CODE_TARGET);
475 } else {
476 __ add(ip, i.InputRegister(0),
477 Operand(Code::kHeaderSize - kHeapObjectTag));
478 __ Call(ip);
479 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 RecordCallPosition(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 DCHECK_EQ(LeaveCC, i.OutputSBit());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 frame_access_state()->ClearSPDelta();
483 break;
484 }
Ben Murdochda12d292016-06-02 14:46:10 +0100485 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 case kArchTailCallCodeObject: {
487 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
488 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100489 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
490 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
491 i.TempRegister(0), i.TempRegister(1),
492 i.TempRegister(2));
493 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 if (instr->InputAt(0)->IsImmediate()) {
495 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
496 RelocInfo::CODE_TARGET);
497 } else {
498 __ add(ip, i.InputRegister(0),
499 Operand(Code::kHeaderSize - kHeapObjectTag));
500 __ Jump(ip);
501 }
502 DCHECK_EQ(LeaveCC, i.OutputSBit());
503 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 break;
505 }
Ben Murdochc5610432016-08-08 18:44:38 +0100506 case kArchTailCallAddress: {
507 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
508 AssembleDeconstructActivationRecord(stack_param_delta);
509 CHECK(!instr->InputAt(0)->IsImmediate());
510 __ Jump(i.InputRegister(0));
511 frame_access_state()->ClearSPDelta();
512 break;
513 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 case kArchCallJSFunction: {
515 EnsureSpaceForLazyDeopt();
516 Register func = i.InputRegister(0);
517 if (FLAG_debug_code) {
518 // Check the function's context matches the context argument.
519 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
520 __ cmp(cp, kScratchReg);
521 __ Assert(eq, kWrongFunctionContext);
522 }
523 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
524 __ Call(ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 RecordCallPosition(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000526 DCHECK_EQ(LeaveCC, i.OutputSBit());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527 frame_access_state()->ClearSPDelta();
528 break;
529 }
Ben Murdochda12d292016-06-02 14:46:10 +0100530 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000531 case kArchTailCallJSFunction: {
532 Register func = i.InputRegister(0);
533 if (FLAG_debug_code) {
534 // Check the function's context matches the context argument.
535 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
536 __ cmp(cp, kScratchReg);
537 __ Assert(eq, kWrongFunctionContext);
538 }
539 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
540 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100541 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
542 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
543 i.TempRegister(0), i.TempRegister(1),
544 i.TempRegister(2));
545 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
547 __ Jump(ip);
548 DCHECK_EQ(LeaveCC, i.OutputSBit());
549 frame_access_state()->ClearSPDelta();
550 break;
551 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 case kArchPrepareCallCFunction: {
553 int const num_parameters = MiscField::decode(instr->opcode());
554 __ PrepareCallCFunction(num_parameters, kScratchReg);
555 // Frame alignment requires using FP-relative frame addressing.
556 frame_access_state()->SetFrameAccessToFP();
557 break;
558 }
559 case kArchPrepareTailCall:
560 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
561 break;
562 case kArchCallCFunction: {
563 int const num_parameters = MiscField::decode(instr->opcode());
564 if (instr->InputAt(0)->IsImmediate()) {
565 ExternalReference ref = i.InputExternalReference(0);
566 __ CallCFunction(ref, num_parameters);
567 } else {
568 Register func = i.InputRegister(0);
569 __ CallCFunction(func, num_parameters);
570 }
571 frame_access_state()->SetFrameAccessToDefault();
572 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 break;
574 }
575 case kArchJmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400576 AssembleArchJump(i.InputRpo(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 DCHECK_EQ(LeaveCC, i.OutputSBit());
578 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 case kArchLookupSwitch:
580 AssembleArchLookupSwitch(instr);
581 DCHECK_EQ(LeaveCC, i.OutputSBit());
582 break;
583 case kArchTableSwitch:
584 AssembleArchTableSwitch(instr);
585 DCHECK_EQ(LeaveCC, i.OutputSBit());
586 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000587 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588 case kArchThrowTerminator:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 // don't emit code for nops.
590 DCHECK_EQ(LeaveCC, i.OutputSBit());
591 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 case kArchDeoptimize: {
593 int deopt_state_id =
594 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
595 Deoptimizer::BailoutType bailout_type =
596 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochc5610432016-08-08 18:44:38 +0100597 CodeGenResult result =
598 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
599 if (result != kSuccess) return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 break;
601 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 case kArchRet:
603 AssembleReturn();
604 DCHECK_EQ(LeaveCC, i.OutputSBit());
605 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400606 case kArchStackPointer:
607 __ mov(i.OutputRegister(), sp);
608 DCHECK_EQ(LeaveCC, i.OutputSBit());
609 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 case kArchFramePointer:
611 __ mov(i.OutputRegister(), fp);
612 DCHECK_EQ(LeaveCC, i.OutputSBit());
613 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100614 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100615 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100616 __ ldr(i.OutputRegister(), MemOperand(fp, 0));
617 } else {
618 __ mov(i.OutputRegister(), fp);
619 }
620 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000621 case kArchTruncateDoubleToI:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400622 __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 DCHECK_EQ(LeaveCC, i.OutputSBit());
624 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625 case kArchStoreWithWriteBarrier: {
626 RecordWriteMode mode =
627 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
628 Register object = i.InputRegister(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 Register value = i.InputRegister(2);
630 Register scratch0 = i.TempRegister(0);
631 Register scratch1 = i.TempRegister(1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100632 OutOfLineRecordWrite* ool;
633
634 AddressingMode addressing_mode =
635 AddressingModeField::decode(instr->opcode());
636 if (addressing_mode == kMode_Offset_RI) {
637 int32_t index = i.InputInt32(1);
638 ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
639 scratch0, scratch1, mode);
640 __ str(value, MemOperand(object, index));
641 } else {
642 DCHECK_EQ(kMode_Offset_RR, addressing_mode);
643 Register index(i.InputRegister(1));
644 ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
645 scratch0, scratch1, mode);
646 __ str(value, MemOperand(object, index));
647 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000648 __ CheckPageFlag(object, scratch0,
649 MemoryChunk::kPointersFromHereAreInterestingMask, ne,
650 ool->entry());
651 __ bind(ool->exit());
652 break;
653 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100654 case kArchStackSlot: {
655 FrameOffset offset =
656 frame_access_state()->GetFrameOffset(i.InputInt32(0));
657 Register base;
658 if (offset.from_stack_pointer()) {
659 base = sp;
660 } else {
661 base = fp;
662 }
663 __ add(i.OutputRegister(0), base, Operand(offset.offset()));
664 break;
665 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666 case kArmAdd:
667 __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
668 i.OutputSBit());
669 break;
670 case kArmAnd:
671 __ and_(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
672 i.OutputSBit());
673 break;
674 case kArmBic:
675 __ bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
676 i.OutputSBit());
677 break;
678 case kArmMul:
679 __ mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
680 i.OutputSBit());
681 break;
682 case kArmMla:
683 __ mla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
684 i.InputRegister(2), i.OutputSBit());
685 break;
686 case kArmMls: {
687 CpuFeatureScope scope(masm(), MLS);
688 __ mls(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
689 i.InputRegister(2));
690 DCHECK_EQ(LeaveCC, i.OutputSBit());
691 break;
692 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400693 case kArmSmmul:
694 __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
695 DCHECK_EQ(LeaveCC, i.OutputSBit());
696 break;
697 case kArmSmmla:
698 __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
699 i.InputRegister(2));
700 DCHECK_EQ(LeaveCC, i.OutputSBit());
701 break;
702 case kArmUmull:
703 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
704 i.InputRegister(1), i.OutputSBit());
705 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 case kArmSdiv: {
707 CpuFeatureScope scope(masm(), SUDIV);
708 __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
709 DCHECK_EQ(LeaveCC, i.OutputSBit());
710 break;
711 }
712 case kArmUdiv: {
713 CpuFeatureScope scope(masm(), SUDIV);
714 __ udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
715 DCHECK_EQ(LeaveCC, i.OutputSBit());
716 break;
717 }
718 case kArmMov:
719 __ Move(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
720 break;
721 case kArmMvn:
722 __ mvn(i.OutputRegister(), i.InputOperand2(0), i.OutputSBit());
723 break;
724 case kArmOrr:
725 __ orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
726 i.OutputSBit());
727 break;
728 case kArmEor:
729 __ eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
730 i.OutputSBit());
731 break;
732 case kArmSub:
733 __ sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
734 i.OutputSBit());
735 break;
736 case kArmRsb:
737 __ rsb(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
738 i.OutputSBit());
739 break;
740 case kArmBfc: {
741 CpuFeatureScope scope(masm(), ARMv7);
742 __ bfc(i.OutputRegister(), i.InputInt8(1), i.InputInt8(2));
743 DCHECK_EQ(LeaveCC, i.OutputSBit());
744 break;
745 }
746 case kArmUbfx: {
747 CpuFeatureScope scope(masm(), ARMv7);
748 __ ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
749 i.InputInt8(2));
750 DCHECK_EQ(LeaveCC, i.OutputSBit());
751 break;
752 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100753 case kArmSbfx: {
754 CpuFeatureScope scope(masm(), ARMv7);
755 __ sbfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
756 i.InputInt8(2));
757 DCHECK_EQ(LeaveCC, i.OutputSBit());
758 break;
759 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400760 case kArmSxtb:
761 __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
762 DCHECK_EQ(LeaveCC, i.OutputSBit());
763 break;
764 case kArmSxth:
765 __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
766 DCHECK_EQ(LeaveCC, i.OutputSBit());
767 break;
768 case kArmSxtab:
769 __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
770 i.InputInt32(2));
771 DCHECK_EQ(LeaveCC, i.OutputSBit());
772 break;
773 case kArmSxtah:
774 __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
775 i.InputInt32(2));
776 DCHECK_EQ(LeaveCC, i.OutputSBit());
777 break;
778 case kArmUxtb:
779 __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
780 DCHECK_EQ(LeaveCC, i.OutputSBit());
781 break;
782 case kArmUxth:
783 __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
784 DCHECK_EQ(LeaveCC, i.OutputSBit());
785 break;
786 case kArmUxtab:
787 __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
788 i.InputInt32(2));
789 DCHECK_EQ(LeaveCC, i.OutputSBit());
790 break;
791 case kArmUxtah:
792 __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
793 i.InputInt32(2));
794 DCHECK_EQ(LeaveCC, i.OutputSBit());
795 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100796 case kArmRbit: {
797 CpuFeatureScope scope(masm(), ARMv7);
798 __ rbit(i.OutputRegister(), i.InputRegister(0));
799 DCHECK_EQ(LeaveCC, i.OutputSBit());
800 break;
801 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000802 case kArmClz:
803 __ clz(i.OutputRegister(), i.InputRegister(0));
804 DCHECK_EQ(LeaveCC, i.OutputSBit());
805 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 case kArmCmp:
807 __ cmp(i.InputRegister(0), i.InputOperand2(1));
808 DCHECK_EQ(SetCC, i.OutputSBit());
809 break;
810 case kArmCmn:
811 __ cmn(i.InputRegister(0), i.InputOperand2(1));
812 DCHECK_EQ(SetCC, i.OutputSBit());
813 break;
814 case kArmTst:
815 __ tst(i.InputRegister(0), i.InputOperand2(1));
816 DCHECK_EQ(SetCC, i.OutputSBit());
817 break;
818 case kArmTeq:
819 __ teq(i.InputRegister(0), i.InputOperand2(1));
820 DCHECK_EQ(SetCC, i.OutputSBit());
821 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100822 case kArmAddPair:
823 // i.InputRegister(0) ... left low word.
824 // i.InputRegister(1) ... left high word.
825 // i.InputRegister(2) ... right low word.
826 // i.InputRegister(3) ... right high word.
827 __ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
828 SBit::SetCC);
829 __ adc(i.OutputRegister(1), i.InputRegister(1),
830 Operand(i.InputRegister(3)));
831 DCHECK_EQ(LeaveCC, i.OutputSBit());
832 break;
833 case kArmSubPair:
834 // i.InputRegister(0) ... left low word.
835 // i.InputRegister(1) ... left high word.
836 // i.InputRegister(2) ... right low word.
837 // i.InputRegister(3) ... right high word.
838 __ sub(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
839 SBit::SetCC);
840 __ sbc(i.OutputRegister(1), i.InputRegister(1),
841 Operand(i.InputRegister(3)));
842 DCHECK_EQ(LeaveCC, i.OutputSBit());
843 break;
844 case kArmMulPair:
845 // i.InputRegister(0) ... left low word.
846 // i.InputRegister(1) ... left high word.
847 // i.InputRegister(2) ... right low word.
848 // i.InputRegister(3) ... right high word.
849 __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
850 i.InputRegister(2));
851 __ mla(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(3),
852 i.OutputRegister(1));
853 __ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1),
854 i.OutputRegister(1));
855 break;
856 case kArmLslPair:
857 if (instr->InputAt(2)->IsImmediate()) {
858 __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
859 i.InputRegister(1), i.InputInt32(2));
860 } else {
861 __ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
862 i.InputRegister(1), kScratchReg, i.InputRegister(2));
863 }
864 break;
865 case kArmLsrPair:
866 if (instr->InputAt(2)->IsImmediate()) {
867 __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
868 i.InputRegister(1), i.InputInt32(2));
869 } else {
870 __ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
871 i.InputRegister(1), kScratchReg, i.InputRegister(2));
872 }
873 break;
874 case kArmAsrPair:
875 if (instr->InputAt(2)->IsImmediate()) {
876 __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
877 i.InputRegister(1), i.InputInt32(2));
878 } else {
879 __ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
880 i.InputRegister(1), kScratchReg, i.InputRegister(2));
881 }
882 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000883 case kArmVcmpF32:
Ben Murdochc5610432016-08-08 18:44:38 +0100884 if (instr->InputAt(1)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885 __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
886 i.InputFloat32Register(1));
887 } else {
888 DCHECK(instr->InputAt(1)->IsImmediate());
889 // 0.0 is the only immediate supported by vcmp instructions.
890 DCHECK(i.InputFloat32(1) == 0.0f);
891 __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputFloat32(1));
892 }
893 DCHECK_EQ(SetCC, i.OutputSBit());
894 break;
895 case kArmVaddF32:
896 __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
897 i.InputFloat32Register(1));
898 DCHECK_EQ(LeaveCC, i.OutputSBit());
899 break;
900 case kArmVsubF32:
901 __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
902 i.InputFloat32Register(1));
903 DCHECK_EQ(LeaveCC, i.OutputSBit());
904 break;
905 case kArmVmulF32:
906 __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
907 i.InputFloat32Register(1));
908 DCHECK_EQ(LeaveCC, i.OutputSBit());
909 break;
910 case kArmVmlaF32:
911 __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
912 i.InputFloat32Register(2));
913 DCHECK_EQ(LeaveCC, i.OutputSBit());
914 break;
915 case kArmVmlsF32:
916 __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
917 i.InputFloat32Register(2));
918 DCHECK_EQ(LeaveCC, i.OutputSBit());
919 break;
920 case kArmVdivF32:
921 __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
922 i.InputFloat32Register(1));
923 DCHECK_EQ(LeaveCC, i.OutputSBit());
924 break;
925 case kArmVsqrtF32:
926 __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
927 break;
928 case kArmVabsF32:
929 __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
930 break;
931 case kArmVnegF32:
932 __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
933 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 case kArmVcmpF64:
Ben Murdochc5610432016-08-08 18:44:38 +0100935 if (instr->InputAt(1)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
937 i.InputFloat64Register(1));
938 } else {
939 DCHECK(instr->InputAt(1)->IsImmediate());
940 // 0.0 is the only immediate supported by vcmp instructions.
941 DCHECK(i.InputDouble(1) == 0.0);
942 __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
943 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 DCHECK_EQ(SetCC, i.OutputSBit());
945 break;
946 case kArmVaddF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400947 __ vadd(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 kArmVsubF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400952 __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
953 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000954 DCHECK_EQ(LeaveCC, i.OutputSBit());
955 break;
956 case kArmVmulF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400957 __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
958 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 DCHECK_EQ(LeaveCC, i.OutputSBit());
960 break;
961 case kArmVmlaF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400962 __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
963 i.InputFloat64Register(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964 DCHECK_EQ(LeaveCC, i.OutputSBit());
965 break;
966 case kArmVmlsF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400967 __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
968 i.InputFloat64Register(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 DCHECK_EQ(LeaveCC, i.OutputSBit());
970 break;
971 case kArmVdivF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400972 __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
973 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974 DCHECK_EQ(LeaveCC, i.OutputSBit());
975 break;
976 case kArmVmodF64: {
977 // TODO(bmeurer): We should really get rid of this special instruction,
978 // and generate a CallAddress instruction instead.
979 FrameScope scope(masm(), StackFrame::MANUAL);
980 __ PrepareCallCFunction(0, 2, kScratchReg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400981 __ MovToFloatParameters(i.InputFloat64Register(0),
982 i.InputFloat64Register(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000983 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
984 0, 2);
985 // Move the result in the double result register.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400986 __ MovFromFloatResult(i.OutputFloat64Register());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987 DCHECK_EQ(LeaveCC, i.OutputSBit());
988 break;
989 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000990 case kArmVsqrtF64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400991 __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993 case kArmVabsF64:
994 __ vabs(i.OutputFloat64Register(), i.InputFloat64Register(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400995 break;
996 case kArmVnegF64:
997 __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
998 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000999 case kArmVrintmF32:
1000 __ vrintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
1001 break;
1002 case kArmVrintmF64:
1003 __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
1004 break;
1005 case kArmVrintpF32:
1006 __ vrintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
1007 break;
1008 case kArmVrintpF64:
1009 __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
1010 break;
1011 case kArmVrintzF32:
1012 __ vrintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
1013 break;
1014 case kArmVrintzF64:
1015 __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
1016 break;
1017 case kArmVrintaF64:
1018 __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
1019 break;
1020 case kArmVrintnF32:
1021 __ vrintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
1022 break;
1023 case kArmVrintnF64:
1024 __ vrintn(i.OutputFloat64Register(), i.InputFloat64Register(0));
1025 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001026 case kArmVcvtF32F64: {
1027 __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
1028 DCHECK_EQ(LeaveCC, i.OutputSBit());
1029 break;
1030 }
1031 case kArmVcvtF64F32: {
1032 __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
1033 DCHECK_EQ(LeaveCC, i.OutputSBit());
1034 break;
1035 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001036 case kArmVcvtF32S32: {
1037 SwVfpRegister scratch = kScratchDoubleReg.low();
1038 __ vmov(scratch, i.InputRegister(0));
1039 __ vcvt_f32_s32(i.OutputFloat32Register(), scratch);
1040 DCHECK_EQ(LeaveCC, i.OutputSBit());
1041 break;
1042 }
1043 case kArmVcvtF32U32: {
1044 SwVfpRegister scratch = kScratchDoubleReg.low();
1045 __ vmov(scratch, i.InputRegister(0));
1046 __ vcvt_f32_u32(i.OutputFloat32Register(), scratch);
1047 DCHECK_EQ(LeaveCC, i.OutputSBit());
1048 break;
1049 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001050 case kArmVcvtF64S32: {
1051 SwVfpRegister scratch = kScratchDoubleReg.low();
1052 __ vmov(scratch, i.InputRegister(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001053 __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001054 DCHECK_EQ(LeaveCC, i.OutputSBit());
1055 break;
1056 }
1057 case kArmVcvtF64U32: {
1058 SwVfpRegister scratch = kScratchDoubleReg.low();
1059 __ vmov(scratch, i.InputRegister(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001060 __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 DCHECK_EQ(LeaveCC, i.OutputSBit());
1062 break;
1063 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001064 case kArmVcvtS32F32: {
1065 SwVfpRegister scratch = kScratchDoubleReg.low();
1066 __ vcvt_s32_f32(scratch, i.InputFloat32Register(0));
1067 __ vmov(i.OutputRegister(), scratch);
1068 DCHECK_EQ(LeaveCC, i.OutputSBit());
1069 break;
1070 }
1071 case kArmVcvtU32F32: {
1072 SwVfpRegister scratch = kScratchDoubleReg.low();
1073 __ vcvt_u32_f32(scratch, i.InputFloat32Register(0));
1074 __ vmov(i.OutputRegister(), scratch);
1075 DCHECK_EQ(LeaveCC, i.OutputSBit());
1076 break;
1077 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078 case kArmVcvtS32F64: {
1079 SwVfpRegister scratch = kScratchDoubleReg.low();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001080 __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001081 __ vmov(i.OutputRegister(), scratch);
1082 DCHECK_EQ(LeaveCC, i.OutputSBit());
1083 break;
1084 }
1085 case kArmVcvtU32F64: {
1086 SwVfpRegister scratch = kScratchDoubleReg.low();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001087 __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001088 __ vmov(i.OutputRegister(), scratch);
1089 DCHECK_EQ(LeaveCC, i.OutputSBit());
1090 break;
1091 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001092 case kArmVmovLowU32F64:
1093 __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
1094 DCHECK_EQ(LeaveCC, i.OutputSBit());
1095 break;
1096 case kArmVmovLowF64U32:
1097 __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
1098 DCHECK_EQ(LeaveCC, i.OutputSBit());
1099 break;
1100 case kArmVmovHighU32F64:
1101 __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
1102 DCHECK_EQ(LeaveCC, i.OutputSBit());
1103 break;
1104 case kArmVmovHighF64U32:
1105 __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
1106 DCHECK_EQ(LeaveCC, i.OutputSBit());
1107 break;
1108 case kArmVmovF64U32U32:
1109 __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
1110 i.InputRegister(1));
1111 DCHECK_EQ(LeaveCC, i.OutputSBit());
1112 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113 case kArmLdrb:
1114 __ ldrb(i.OutputRegister(), i.InputOffset());
1115 DCHECK_EQ(LeaveCC, i.OutputSBit());
1116 break;
1117 case kArmLdrsb:
1118 __ ldrsb(i.OutputRegister(), i.InputOffset());
1119 DCHECK_EQ(LeaveCC, i.OutputSBit());
1120 break;
1121 case kArmStrb: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123 MemOperand operand = i.InputOffset(&index);
1124 __ strb(i.InputRegister(index), operand);
1125 DCHECK_EQ(LeaveCC, i.OutputSBit());
1126 break;
1127 }
1128 case kArmLdrh:
1129 __ ldrh(i.OutputRegister(), i.InputOffset());
1130 break;
1131 case kArmLdrsh:
1132 __ ldrsh(i.OutputRegister(), i.InputOffset());
1133 break;
1134 case kArmStrh: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001135 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001136 MemOperand operand = i.InputOffset(&index);
1137 __ strh(i.InputRegister(index), operand);
1138 DCHECK_EQ(LeaveCC, i.OutputSBit());
1139 break;
1140 }
1141 case kArmLdr:
1142 __ ldr(i.OutputRegister(), i.InputOffset());
1143 break;
1144 case kArmStr: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 MemOperand operand = i.InputOffset(&index);
1147 __ str(i.InputRegister(index), operand);
1148 DCHECK_EQ(LeaveCC, i.OutputSBit());
1149 break;
1150 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001151 case kArmVldrF32: {
1152 __ vldr(i.OutputFloat32Register(), i.InputOffset());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 DCHECK_EQ(LeaveCC, i.OutputSBit());
1154 break;
1155 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001156 case kArmVstrF32: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 MemOperand operand = i.InputOffset(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001159 __ vstr(i.InputFloat32Register(index), operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 DCHECK_EQ(LeaveCC, i.OutputSBit());
1161 break;
1162 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001163 case kArmVldrF64:
1164 __ vldr(i.OutputFloat64Register(), i.InputOffset());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001165 DCHECK_EQ(LeaveCC, i.OutputSBit());
1166 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001167 case kArmVstrF64: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001168 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001169 MemOperand operand = i.InputOffset(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001170 __ vstr(i.InputFloat64Register(index), operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001171 DCHECK_EQ(LeaveCC, i.OutputSBit());
1172 break;
1173 }
Ben Murdochc5610432016-08-08 18:44:38 +01001174 case kArmFloat32Max: {
1175 CpuFeatureScope scope(masm(), ARMv8);
1176 // (b < a) ? a : b
1177 SwVfpRegister a = i.InputFloat32Register(0);
1178 SwVfpRegister b = i.InputFloat32Register(1);
1179 SwVfpRegister result = i.OutputFloat32Register(0);
1180 __ VFPCompareAndSetFlags(a, b);
1181 __ vsel(gt, result, a, b);
1182 break;
1183 }
1184 case kArmFloat32Min: {
1185 CpuFeatureScope scope(masm(), ARMv8);
1186 // (a < b) ? a : b
1187 SwVfpRegister a = i.InputFloat32Register(0);
1188 SwVfpRegister b = i.InputFloat32Register(1);
1189 SwVfpRegister result = i.OutputFloat32Register(0);
1190 __ VFPCompareAndSetFlags(b, a);
1191 __ vsel(gt, result, a, b);
1192 break;
1193 }
1194 case kArmFloat64Max: {
1195 CpuFeatureScope scope(masm(), ARMv8);
1196 // (b < a) ? a : b
1197 DwVfpRegister a = i.InputFloat64Register(0);
1198 DwVfpRegister b = i.InputFloat64Register(1);
1199 DwVfpRegister result = i.OutputFloat64Register(0);
1200 __ VFPCompareAndSetFlags(a, b);
1201 __ vsel(gt, result, a, b);
1202 break;
1203 }
1204 case kArmFloat64Min: {
1205 CpuFeatureScope scope(masm(), ARMv8);
1206 // (a < b) ? a : b
1207 DwVfpRegister a = i.InputFloat64Register(0);
1208 DwVfpRegister b = i.InputFloat64Register(1);
1209 DwVfpRegister result = i.OutputFloat64Register(0);
1210 __ VFPCompareAndSetFlags(b, a);
1211 __ vsel(gt, result, a, b);
1212 break;
1213 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 case kArmPush:
Ben Murdochc5610432016-08-08 18:44:38 +01001215 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216 __ vpush(i.InputDoubleRegister(0));
1217 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1218 } else {
1219 __ push(i.InputRegister(0));
1220 frame_access_state()->IncreaseSPDelta(1);
1221 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222 DCHECK_EQ(LeaveCC, i.OutputSBit());
1223 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001224 case kArmPoke: {
1225 int const slot = MiscField::decode(instr->opcode());
1226 __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 DCHECK_EQ(LeaveCC, i.OutputSBit());
1228 break;
1229 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001230 case kCheckedLoadInt8:
1231 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
1232 break;
1233 case kCheckedLoadUint8:
1234 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
1235 break;
1236 case kCheckedLoadInt16:
1237 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
1238 break;
1239 case kCheckedLoadUint16:
1240 ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
1241 break;
1242 case kCheckedLoadWord32:
1243 ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
1244 break;
1245 case kCheckedLoadFloat32:
1246 ASSEMBLE_CHECKED_LOAD_FLOAT(32);
1247 break;
1248 case kCheckedLoadFloat64:
1249 ASSEMBLE_CHECKED_LOAD_FLOAT(64);
1250 break;
1251 case kCheckedStoreWord8:
1252 ASSEMBLE_CHECKED_STORE_INTEGER(strb);
1253 break;
1254 case kCheckedStoreWord16:
1255 ASSEMBLE_CHECKED_STORE_INTEGER(strh);
1256 break;
1257 case kCheckedStoreWord32:
1258 ASSEMBLE_CHECKED_STORE_INTEGER(str);
1259 break;
1260 case kCheckedStoreFloat32:
1261 ASSEMBLE_CHECKED_STORE_FLOAT(32);
1262 break;
1263 case kCheckedStoreFloat64:
1264 ASSEMBLE_CHECKED_STORE_FLOAT(64);
1265 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 case kCheckedLoadWord64:
1267 case kCheckedStoreWord64:
1268 UNREACHABLE(); // currently unsupported checked int64 load/store.
1269 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001270
1271 case kAtomicLoadInt8:
1272 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsb);
1273 break;
1274 case kAtomicLoadUint8:
1275 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrb);
1276 break;
1277 case kAtomicLoadInt16:
1278 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrsh);
1279 break;
1280 case kAtomicLoadUint16:
1281 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldrh);
1282 break;
1283 case kAtomicLoadWord32:
1284 ASSEMBLE_ATOMIC_LOAD_INTEGER(ldr);
1285 break;
1286
1287 case kAtomicStoreWord8:
1288 ASSEMBLE_ATOMIC_STORE_INTEGER(strb);
1289 break;
1290 case kAtomicStoreWord16:
1291 ASSEMBLE_ATOMIC_STORE_INTEGER(strh);
1292 break;
1293 case kAtomicStoreWord32:
1294 ASSEMBLE_ATOMIC_STORE_INTEGER(str);
1295 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 }
Ben Murdochc5610432016-08-08 18:44:38 +01001297 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001298} // NOLINT(readability/fn_size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299
1300
1301// Assembles branches after an instruction.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001302void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001303 ArmOperandConverter i(this, instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001304 Label* tlabel = branch->true_label;
1305 Label* flabel = branch->false_label;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001306 Condition cc = FlagsConditionToCondition(branch->condition);
1307 __ b(cc, tlabel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001308 if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
1309}
1310
1311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001313 if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001314}
1315
1316
1317// Assembles boolean materializations after an instruction.
1318void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1319 FlagsCondition condition) {
1320 ArmOperandConverter i(this, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001321
1322 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1323 // last output of the instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324 DCHECK_NE(0u, instr->OutputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001325 Register reg = i.OutputRegister(instr->OutputCount() - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326 Condition cc = FlagsConditionToCondition(condition);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 __ mov(reg, Operand(0));
1328 __ mov(reg, Operand(1), LeaveCC, cc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329}
1330
1331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001332void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1333 ArmOperandConverter i(this, instr);
1334 Register input = i.InputRegister(0);
1335 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1336 __ cmp(input, Operand(i.InputInt32(index + 0)));
1337 __ b(eq, GetLabel(i.InputRpo(index + 1)));
1338 }
1339 AssembleArchJump(i.InputRpo(1));
1340}
1341
1342
1343void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1344 ArmOperandConverter i(this, instr);
1345 Register input = i.InputRegister(0);
1346 size_t const case_count = instr->InputCount() - 2;
1347 // Ensure to emit the constant pool first if necessary.
1348 __ CheckConstPool(true, true);
1349 __ cmp(input, Operand(case_count));
1350 __ BlockConstPoolFor(case_count + 2);
1351 __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo);
1352 __ b(GetLabel(i.InputRpo(1)));
1353 for (size_t index = 0; index < case_count; ++index) {
1354 __ b(GetLabel(i.InputRpo(index + 2)));
1355 }
1356}
1357
Ben Murdochc5610432016-08-08 18:44:38 +01001358CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 isolate(), deoptimization_id, bailout_type);
Ben Murdochda12d292016-06-02 14:46:10 +01001362 // TODO(turbofan): We should be able to generate better code by sharing the
1363 // actual final call site and just bl'ing to it here, similar to what we do
1364 // in the lithium backend.
Ben Murdochc5610432016-08-08 18:44:38 +01001365 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001366 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochda12d292016-06-02 14:46:10 +01001367 __ CheckConstPool(false, false);
Ben Murdochc5610432016-08-08 18:44:38 +01001368 return kSuccess;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369}
1370
Ben Murdochc5610432016-08-08 18:44:38 +01001371void CodeGenerator::FinishFrame(Frame* frame) {
1372 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373
Ben Murdochc5610432016-08-08 18:44:38 +01001374 const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
1375 if (saves_fp != 0) {
1376 frame->AlignSavedCalleeRegisterSlots();
1377 }
1378
1379 if (saves_fp != 0) {
1380 // Save callee-saved FP registers.
1381 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
1382 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
1383 uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
1384 DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
1385 frame->AllocateSavedCalleeRegisterSlots((last - first + 1) *
1386 (kDoubleSize / kPointerSize));
1387 }
1388 const RegList saves = FLAG_enable_embedded_constant_pool
1389 ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
1390 : descriptor->CalleeSavedRegisters();
1391 if (saves != 0) {
1392 // Save callee-saved registers.
1393 frame->AllocateSavedCalleeRegisterSlots(
1394 base::bits::CountPopulation32(saves));
1395 }
1396}
1397
1398void CodeGenerator::AssembleConstructFrame() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001399 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01001400 if (frame_access_state()->has_frame()) {
1401 if (descriptor->IsCFunctionCall()) {
1402 if (FLAG_enable_embedded_constant_pool) {
1403 __ Push(lr, fp, pp);
1404 // Adjust FP to point to saved FP.
1405 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
1406 } else {
1407 __ Push(lr, fp);
1408 __ mov(fp, sp);
1409 }
1410 } else if (descriptor->IsJSFunctionCall()) {
1411 __ Prologue(this->info()->GeneratePreagedPrologue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001413 __ StubPrologue(info()->GetOutputStackFrameType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001415 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001416
Ben Murdochc5610432016-08-08 18:44:38 +01001417 int shrink_slots = frame()->GetSpillSlotCount();
1418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 if (info()->is_osr()) {
1420 // TurboFan OSR-compiled functions cannot be entered directly.
1421 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1422
1423 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1424 // frame is still on the stack. Optimized code uses OSR values directly from
1425 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1426 // remaining stack slots.
1427 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1428 osr_pc_offset_ = __ pc_offset();
Ben Murdochc5610432016-08-08 18:44:38 +01001429 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001430 }
1431
1432 const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
Ben Murdochc5610432016-08-08 18:44:38 +01001433 if (shrink_slots > 0) {
1434 __ sub(sp, sp, Operand(shrink_slots * kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 }
1436
1437 if (saves_fp != 0) {
1438 // Save callee-saved FP registers.
1439 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
1440 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
1441 uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
1442 DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
1443 __ vstm(db_w, sp, DwVfpRegister::from_code(first),
1444 DwVfpRegister::from_code(last));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001445 }
1446 const RegList saves = FLAG_enable_embedded_constant_pool
1447 ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
1448 : descriptor->CalleeSavedRegisters();
1449 if (saves != 0) {
1450 // Save callee-saved registers.
1451 __ stm(db_w, sp, saves);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452 }
1453}
1454
1455
1456void CodeGenerator::AssembleReturn() {
1457 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458 int pop_count = static_cast<int>(descriptor->StackParameterCount());
1459
1460 // Restore registers.
1461 const RegList saves = FLAG_enable_embedded_constant_pool
1462 ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
1463 : descriptor->CalleeSavedRegisters();
1464 if (saves != 0) {
1465 __ ldm(ia_w, sp, saves);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467
1468 // Restore FP registers.
1469 const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
1470 if (saves_fp != 0) {
1471 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
1472 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
1473 uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
1474 __ vldm(ia_w, sp, DwVfpRegister::from_code(first),
1475 DwVfpRegister::from_code(last));
1476 }
1477
1478 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001479 AssembleDeconstructFrame();
1480 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 // Canonicalize JSFunction return sites for now.
1482 if (return_label_.is_bound()) {
1483 __ b(&return_label_);
1484 return;
1485 } else {
1486 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01001487 AssembleDeconstructFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001488 }
1489 }
1490 __ Ret(pop_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491}
1492
1493
1494void CodeGenerator::AssembleMove(InstructionOperand* source,
1495 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001496 ArmOperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497 // Dispatch on the source and destination operand kinds. Not all
1498 // combinations are possible.
1499 if (source->IsRegister()) {
1500 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1501 Register src = g.ToRegister(source);
1502 if (destination->IsRegister()) {
1503 __ mov(g.ToRegister(destination), src);
1504 } else {
1505 __ str(src, g.ToMemOperand(destination));
1506 }
1507 } else if (source->IsStackSlot()) {
1508 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1509 MemOperand src = g.ToMemOperand(source);
1510 if (destination->IsRegister()) {
1511 __ ldr(g.ToRegister(destination), src);
1512 } else {
1513 Register temp = kScratchReg;
1514 __ ldr(temp, src);
1515 __ str(temp, g.ToMemOperand(destination));
1516 }
1517 } else if (source->IsConstant()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001518 Constant src = g.ToConstant(source);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 if (destination->IsRegister() || destination->IsStackSlot()) {
1520 Register dst =
1521 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522 switch (src.type()) {
1523 case Constant::kInt32:
Ben Murdochc5610432016-08-08 18:44:38 +01001524 if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
1525 src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
1526 __ mov(dst, Operand(src.ToInt32(), src.rmode()));
1527 } else {
1528 __ mov(dst, Operand(src.ToInt32()));
1529 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001530 break;
1531 case Constant::kInt64:
1532 UNREACHABLE();
1533 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001534 case Constant::kFloat32:
1535 __ Move(dst,
1536 isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1537 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001538 case Constant::kFloat64:
1539 __ Move(dst,
1540 isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1541 break;
1542 case Constant::kExternalReference:
1543 __ mov(dst, Operand(src.ToExternalReference()));
1544 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 case Constant::kHeapObject: {
1546 Handle<HeapObject> src_object = src.ToHeapObject();
1547 Heap::RootListIndex index;
Ben Murdochda12d292016-06-02 14:46:10 +01001548 int slot;
1549 if (IsMaterializableFromFrame(src_object, &slot)) {
1550 __ ldr(dst, g.SlotToMemOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 } else if (IsMaterializableFromRoot(src_object, &index)) {
1552 __ LoadRoot(dst, index);
1553 } else {
1554 __ Move(dst, src_object);
1555 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001556 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001558 case Constant::kRpoNumber:
1559 UNREACHABLE(); // TODO(dcarney): loading RPO constants on arm.
1560 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 }
1562 if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001563 } else if (src.type() == Constant::kFloat32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001564 if (destination->IsFPStackSlot()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001565 MemOperand dst = g.ToMemOperand(destination);
1566 __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
1567 __ str(ip, dst);
1568 } else {
1569 SwVfpRegister dst = g.ToFloat32Register(destination);
1570 __ vmov(dst, src.ToFloat32());
1571 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001573 DCHECK_EQ(Constant::kFloat64, src.type());
Ben Murdochc5610432016-08-08 18:44:38 +01001574 DwVfpRegister dst = destination->IsFPRegister()
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001575 ? g.ToFloat64Register(destination)
1576 : kScratchDoubleReg;
1577 __ vmov(dst, src.ToFloat64(), kScratchReg);
Ben Murdochc5610432016-08-08 18:44:38 +01001578 if (destination->IsFPStackSlot()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001579 __ vstr(dst, g.ToMemOperand(destination));
1580 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 }
Ben Murdochc5610432016-08-08 18:44:38 +01001582 } else if (source->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583 DwVfpRegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001584 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001585 DwVfpRegister dst = g.ToDoubleRegister(destination);
1586 __ Move(dst, src);
1587 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001588 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 __ vstr(src, g.ToMemOperand(destination));
1590 }
Ben Murdochc5610432016-08-08 18:44:38 +01001591 } else if (source->IsFPStackSlot()) {
1592 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 MemOperand src = g.ToMemOperand(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001594 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595 __ vldr(g.ToDoubleRegister(destination), src);
1596 } else {
1597 DwVfpRegister temp = kScratchDoubleReg;
1598 __ vldr(temp, src);
1599 __ vstr(temp, g.ToMemOperand(destination));
1600 }
1601 } else {
1602 UNREACHABLE();
1603 }
1604}
1605
1606
1607void CodeGenerator::AssembleSwap(InstructionOperand* source,
1608 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001609 ArmOperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001610 // Dispatch on the source and destination operand kinds. Not all
1611 // combinations are possible.
1612 if (source->IsRegister()) {
1613 // Register-register.
1614 Register temp = kScratchReg;
1615 Register src = g.ToRegister(source);
1616 if (destination->IsRegister()) {
1617 Register dst = g.ToRegister(destination);
1618 __ Move(temp, src);
1619 __ Move(src, dst);
1620 __ Move(dst, temp);
1621 } else {
1622 DCHECK(destination->IsStackSlot());
1623 MemOperand dst = g.ToMemOperand(destination);
1624 __ mov(temp, src);
1625 __ ldr(src, dst);
1626 __ str(temp, dst);
1627 }
1628 } else if (source->IsStackSlot()) {
1629 DCHECK(destination->IsStackSlot());
1630 Register temp_0 = kScratchReg;
1631 SwVfpRegister temp_1 = kScratchDoubleReg.low();
1632 MemOperand src = g.ToMemOperand(source);
1633 MemOperand dst = g.ToMemOperand(destination);
1634 __ ldr(temp_0, src);
1635 __ vldr(temp_1, dst);
1636 __ str(temp_0, dst);
1637 __ vstr(temp_1, src);
Ben Murdochc5610432016-08-08 18:44:38 +01001638 } else if (source->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 DwVfpRegister temp = kScratchDoubleReg;
1640 DwVfpRegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001641 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 DwVfpRegister dst = g.ToDoubleRegister(destination);
1643 __ Move(temp, src);
1644 __ Move(src, dst);
1645 __ Move(dst, temp);
1646 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001647 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001648 MemOperand dst = g.ToMemOperand(destination);
1649 __ Move(temp, src);
1650 __ vldr(src, dst);
1651 __ vstr(temp, dst);
1652 }
Ben Murdochc5610432016-08-08 18:44:38 +01001653 } else if (source->IsFPStackSlot()) {
1654 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655 Register temp_0 = kScratchReg;
1656 DwVfpRegister temp_1 = kScratchDoubleReg;
1657 MemOperand src0 = g.ToMemOperand(source);
1658 MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
1659 MemOperand dst0 = g.ToMemOperand(destination);
1660 MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
1661 __ vldr(temp_1, dst0); // Save destination in temp_1.
1662 __ ldr(temp_0, src0); // Then use temp_0 to copy source to destination.
1663 __ str(temp_0, dst0);
1664 __ ldr(temp_0, src1);
1665 __ str(temp_0, dst1);
1666 __ vstr(temp_1, src0);
1667 } else {
1668 // No other combinations are possible.
1669 UNREACHABLE();
1670 }
1671}
1672
1673
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001674void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1675 // On 32-bit ARM we emit the jump tables inline.
1676 UNREACHABLE();
1677}
1678
1679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001681 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1682 return;
1683 }
1684
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 int space_needed = Deoptimizer::patch_size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001686 // Ensure that we have enough space after the previous lazy-bailout
1687 // instruction for patching the code here.
1688 int current_pc = masm()->pc_offset();
1689 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1690 // Block literal pool emission for duration of padding.
1691 v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
1692 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1693 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1694 while (padding_size > 0) {
1695 __ nop();
1696 padding_size -= v8::internal::Assembler::kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697 }
1698 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699}
1700
1701#undef __
1702
1703} // namespace compiler
1704} // namespace internal
1705} // namespace v8