blob: a9083e13510e855c38ec96cdfbe3d11c858e9781 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/ast/scopes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/compiler/code-generator-impl.h"
9#include "src/compiler/gap-resolver.h"
10#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/compiler/osr.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/frames.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/ia32/assembler-ia32.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/ia32/frames-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/ia32/macro-assembler-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016
17namespace v8 {
18namespace internal {
19namespace compiler {
20
21#define __ masm()->
22
23
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000024#define kScratchDoubleReg xmm0
25
26
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027// Adds IA-32 specific methods for decoding operands.
28class IA32OperandConverter : public InstructionOperandConverter {
29 public:
30 IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
31 : InstructionOperandConverter(gen, instr) {}
32
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 Operand InputOperand(size_t index, int extra = 0) {
34 return ToOperand(instr_->InputAt(index), extra);
35 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 Immediate InputImmediate(size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000038 return ToImmediate(instr_->InputAt(index));
39 }
40
41 Operand OutputOperand() { return ToOperand(instr_->Output()); }
42
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 Operand ToOperand(InstructionOperand* op, int extra = 0) {
44 if (op->IsRegister()) {
45 DCHECK(extra == 0);
46 return Operand(ToRegister(op));
Ben Murdochc5610432016-08-08 18:44:38 +010047 } else if (op->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048 DCHECK(extra == 0);
49 return Operand(ToDoubleRegister(op));
50 }
Ben Murdochc5610432016-08-08 18:44:38 +010051 DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
Ben Murdochda12d292016-06-02 14:46:10 +010052 return SlotToOperand(AllocatedOperand::cast(op)->index(), extra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 }
54
Ben Murdochda12d292016-06-02 14:46:10 +010055 Operand SlotToOperand(int slot, int extra = 0) {
56 FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
57 return Operand(offset.from_stack_pointer() ? esp : ebp,
58 offset.offset() + extra);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059 }
60
61 Operand HighOperand(InstructionOperand* op) {
Ben Murdochc5610432016-08-08 18:44:38 +010062 DCHECK(op->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 return ToOperand(op, kPointerSize);
64 }
65
66 Immediate ToImmediate(InstructionOperand* operand) {
67 Constant constant = ToConstant(operand);
Ben Murdochc5610432016-08-08 18:44:38 +010068 if (constant.type() == Constant::kInt32 &&
69 (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
70 constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) {
71 return Immediate(reinterpret_cast<Address>(constant.ToInt32()),
72 constant.rmode());
73 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 switch (constant.type()) {
75 case Constant::kInt32:
76 return Immediate(constant.ToInt32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040077 case Constant::kFloat32:
78 return Immediate(
79 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 case Constant::kFloat64:
81 return Immediate(
82 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
83 case Constant::kExternalReference:
84 return Immediate(constant.ToExternalReference());
85 case Constant::kHeapObject:
86 return Immediate(constant.ToHeapObject());
87 case Constant::kInt64:
88 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040089 case Constant::kRpoNumber:
90 return Immediate::CodeRelativeOffset(ToLabel(operand));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 }
92 UNREACHABLE();
93 return Immediate(-1);
94 }
95
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 static size_t NextOffset(size_t* offset) {
97 size_t i = *offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 (*offset)++;
99 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 }
101
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400102 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
103 STATIC_ASSERT(0 == static_cast<int>(times_1));
104 STATIC_ASSERT(1 == static_cast<int>(times_2));
105 STATIC_ASSERT(2 == static_cast<int>(times_4));
106 STATIC_ASSERT(3 == static_cast<int>(times_8));
107 int scale = static_cast<int>(mode - one);
108 DCHECK(scale >= 0 && scale < 4);
109 return static_cast<ScaleFactor>(scale);
110 }
111
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 Operand MemoryOperand(size_t* offset) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400113 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
114 switch (mode) {
115 case kMode_MR: {
116 Register base = InputRegister(NextOffset(offset));
117 int32_t disp = 0;
118 return Operand(base, disp);
119 }
120 case kMode_MRI: {
121 Register base = InputRegister(NextOffset(offset));
122 int32_t disp = InputInt32(NextOffset(offset));
123 return Operand(base, disp);
124 }
125 case kMode_MR1:
126 case kMode_MR2:
127 case kMode_MR4:
128 case kMode_MR8: {
129 Register base = InputRegister(NextOffset(offset));
130 Register index = InputRegister(NextOffset(offset));
131 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
132 int32_t disp = 0;
133 return Operand(base, index, scale, disp);
134 }
135 case kMode_MR1I:
136 case kMode_MR2I:
137 case kMode_MR4I:
138 case kMode_MR8I: {
139 Register base = InputRegister(NextOffset(offset));
140 Register index = InputRegister(NextOffset(offset));
141 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
142 int32_t disp = InputInt32(NextOffset(offset));
143 return Operand(base, index, scale, disp);
144 }
145 case kMode_M1:
146 case kMode_M2:
147 case kMode_M4:
148 case kMode_M8: {
149 Register index = InputRegister(NextOffset(offset));
150 ScaleFactor scale = ScaleFor(kMode_M1, mode);
151 int32_t disp = 0;
152 return Operand(index, scale, disp);
153 }
154 case kMode_M1I:
155 case kMode_M2I:
156 case kMode_M4I:
157 case kMode_M8I: {
158 Register index = InputRegister(NextOffset(offset));
159 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
160 int32_t disp = InputInt32(NextOffset(offset));
161 return Operand(index, scale, disp);
162 }
163 case kMode_MI: {
164 int32_t disp = InputInt32(NextOffset(offset));
165 return Operand(Immediate(disp));
166 }
167 case kMode_None:
168 UNREACHABLE();
169 return Operand(no_reg, 0);
170 }
171 UNREACHABLE();
172 return Operand(no_reg, 0);
173 }
174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000175 Operand MemoryOperand(size_t first_input = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 return MemoryOperand(&first_input);
177 }
178};
179
180
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181namespace {
182
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183bool HasImmediateInput(Instruction* instr, size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 return instr->InputAt(index)->IsImmediate();
185}
186
187
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 public:
190 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
191 : OutOfLineCode(gen), result_(result) {}
192
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 void Generate() final { __ xor_(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194
195 private:
196 Register const result_;
197};
198
199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200class OutOfLineLoadFloat final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400201 public:
202 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
203 : OutOfLineCode(gen), result_(result) {}
204
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 void Generate() final { __ pcmpeqd(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206
207 private:
208 XMMRegister const result_;
209};
210
211
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213 public:
214 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
215 XMMRegister input)
216 : OutOfLineCode(gen), result_(result), input_(input) {}
217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 void Generate() final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219 __ sub(esp, Immediate(kDoubleSize));
220 __ movsd(MemOperand(esp, 0), input_);
221 __ SlowTruncateToI(result_, esp, 0);
222 __ add(esp, Immediate(kDoubleSize));
223 }
224
225 private:
226 Register const result_;
227 XMMRegister const input_;
228};
229
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230
231class OutOfLineRecordWrite final : public OutOfLineCode {
232 public:
233 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
234 Register value, Register scratch0, Register scratch1,
235 RecordWriteMode mode)
236 : OutOfLineCode(gen),
237 object_(object),
238 operand_(operand),
239 value_(value),
240 scratch0_(scratch0),
241 scratch1_(scratch1),
242 mode_(mode) {}
243
244 void Generate() final {
245 if (mode_ > RecordWriteMode::kValueIsPointer) {
246 __ JumpIfSmi(value_, exit());
247 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100248 __ CheckPageFlag(value_, scratch0_,
249 MemoryChunk::kPointersToHereAreInterestingMask, zero,
250 exit());
251 RememberedSetAction const remembered_set_action =
252 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
253 : OMIT_REMEMBERED_SET;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 SaveFPRegsMode const save_fp_mode =
255 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
256 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100257 remembered_set_action, save_fp_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 __ lea(scratch1_, operand_);
259 __ CallStub(&stub);
260 }
261
262 private:
263 Register const object_;
264 Operand const operand_;
265 Register const value_;
266 Register const scratch0_;
267 Register const scratch1_;
268 RecordWriteMode const mode_;
269};
270
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271} // namespace
272
273
274#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
275 do { \
276 auto result = i.OutputDoubleRegister(); \
277 auto offset = i.InputRegister(0); \
278 if (instr->InputAt(1)->IsRegister()) { \
279 __ cmp(offset, i.InputRegister(1)); \
280 } else { \
281 __ cmp(offset, i.InputImmediate(1)); \
282 } \
283 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
284 __ j(above_equal, ool->entry()); \
285 __ asm_instr(result, i.MemoryOperand(2)); \
286 __ bind(ool->exit()); \
287 } while (false)
288
289
290#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
291 do { \
292 auto result = i.OutputRegister(); \
293 auto offset = i.InputRegister(0); \
294 if (instr->InputAt(1)->IsRegister()) { \
295 __ cmp(offset, i.InputRegister(1)); \
296 } else { \
297 __ cmp(offset, i.InputImmediate(1)); \
298 } \
299 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
300 __ j(above_equal, ool->entry()); \
301 __ asm_instr(result, i.MemoryOperand(2)); \
302 __ bind(ool->exit()); \
303 } while (false)
304
305
306#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
307 do { \
308 auto offset = i.InputRegister(0); \
309 if (instr->InputAt(1)->IsRegister()) { \
310 __ cmp(offset, i.InputRegister(1)); \
311 } else { \
312 __ cmp(offset, i.InputImmediate(1)); \
313 } \
314 Label done; \
315 __ j(above_equal, &done, Label::kNear); \
316 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
317 __ bind(&done); \
318 } while (false)
319
320
321#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
322 do { \
323 auto offset = i.InputRegister(0); \
324 if (instr->InputAt(1)->IsRegister()) { \
325 __ cmp(offset, i.InputRegister(1)); \
326 } else { \
327 __ cmp(offset, i.InputImmediate(1)); \
328 } \
329 Label done; \
330 __ j(above_equal, &done, Label::kNear); \
331 if (instr->InputAt(2)->IsRegister()) { \
332 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
333 } else { \
334 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
335 } \
336 __ bind(&done); \
337 } while (false)
338
Ben Murdochda12d292016-06-02 14:46:10 +0100339#define ASSEMBLE_COMPARE(asm_instr) \
340 do { \
341 if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
342 size_t index = 0; \
343 Operand left = i.MemoryOperand(&index); \
344 if (HasImmediateInput(instr, index)) { \
345 __ asm_instr(left, i.InputImmediate(index)); \
346 } else { \
347 __ asm_instr(left, i.InputRegister(index)); \
348 } \
349 } else { \
350 if (HasImmediateInput(instr, 1)) { \
351 if (instr->InputAt(0)->IsRegister()) { \
352 __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
353 } else { \
354 __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
355 } \
356 } else { \
357 if (instr->InputAt(1)->IsRegister()) { \
358 __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
359 } else { \
360 __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
361 } \
362 } \
363 } \
364 } while (0)
365
366void CodeGenerator::AssembleDeconstructFrame() {
367 __ mov(esp, ebp);
368 __ pop(ebp);
369}
370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
372 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
373 if (sp_slot_delta > 0) {
374 __ add(esp, Immediate(sp_slot_delta * kPointerSize));
375 }
376 frame_access_state()->SetFrameAccessToDefault();
377}
378
379
380void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
381 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
382 if (sp_slot_delta < 0) {
383 __ sub(esp, Immediate(-sp_slot_delta * kPointerSize));
384 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
385 }
Ben Murdochda12d292016-06-02 14:46:10 +0100386 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000387 __ mov(ebp, MemOperand(ebp, 0));
388 }
389 frame_access_state()->SetFrameAccessToSP();
390}
391
Ben Murdochda12d292016-06-02 14:46:10 +0100392void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
393 Register, Register,
394 Register) {
395 // There are not enough temp registers left on ia32 for a call instruction
396 // so we pick some scratch registers and save/restore them manually here.
397 int scratch_count = 3;
398 Register scratch1 = ebx;
399 Register scratch2 = ecx;
400 Register scratch3 = edx;
401 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
402 Label done;
403
404 // Check if current frame is an arguments adaptor frame.
405 __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset),
406 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
407 __ j(not_equal, &done, Label::kNear);
408
409 __ push(scratch1);
410 __ push(scratch2);
411 __ push(scratch3);
412
413 // Load arguments count from current arguments adaptor frame (note, it
414 // does not include receiver).
415 Register caller_args_count_reg = scratch1;
416 __ mov(caller_args_count_reg,
417 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
418 __ SmiUntag(caller_args_count_reg);
419
420 ParameterCount callee_args_count(args_reg);
421 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
422 scratch3, ReturnAddressState::kOnStack, scratch_count);
423 __ pop(scratch3);
424 __ pop(scratch2);
425 __ pop(scratch1);
426
427 __ bind(&done);
428}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430// Assembles an instruction after register allocation, producing machine code.
Ben Murdochc5610432016-08-08 18:44:38 +0100431CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
432 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 IA32OperandConverter i(this, instr);
Ben Murdochda12d292016-06-02 14:46:10 +0100434 InstructionCode opcode = instr->opcode();
435 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
436 switch (arch_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 case kArchCallCodeObject: {
438 EnsureSpaceForLazyDeopt();
439 if (HasImmediateInput(instr, 0)) {
440 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
441 __ call(code, RelocInfo::CODE_TARGET);
442 } else {
443 Register reg = i.InputRegister(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
445 __ call(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 RecordCallPosition(instr);
448 frame_access_state()->ClearSPDelta();
449 break;
450 }
Ben Murdochda12d292016-06-02 14:46:10 +0100451 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 case kArchTailCallCodeObject: {
453 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
454 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100455 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
456 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
457 no_reg, no_reg, no_reg);
458 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 if (HasImmediateInput(instr, 0)) {
460 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
461 __ jmp(code, RelocInfo::CODE_TARGET);
462 } else {
463 Register reg = i.InputRegister(0);
464 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
465 __ jmp(reg);
466 }
467 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 break;
469 }
Ben Murdochc5610432016-08-08 18:44:38 +0100470 case kArchTailCallAddress: {
471 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
472 AssembleDeconstructActivationRecord(stack_param_delta);
473 CHECK(!HasImmediateInput(instr, 0));
474 Register reg = i.InputRegister(0);
475 __ jmp(reg);
476 frame_access_state()->ClearSPDelta();
477 break;
478 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 case kArchCallJSFunction: {
480 EnsureSpaceForLazyDeopt();
481 Register func = i.InputRegister(0);
482 if (FLAG_debug_code) {
483 // Check the function's context matches the context argument.
484 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
485 __ Assert(equal, kWrongFunctionContext);
486 }
487 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 RecordCallPosition(instr);
489 frame_access_state()->ClearSPDelta();
490 break;
491 }
Ben Murdochda12d292016-06-02 14:46:10 +0100492 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 case kArchTailCallJSFunction: {
494 Register func = i.InputRegister(0);
495 if (FLAG_debug_code) {
496 // Check the function's context matches the context argument.
497 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
498 __ Assert(equal, kWrongFunctionContext);
499 }
500 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
501 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100502 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
503 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
504 no_reg, no_reg, no_reg);
505 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
507 frame_access_state()->ClearSPDelta();
508 break;
509 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 case kArchPrepareCallCFunction: {
511 // Frame alignment requires using FP-relative frame addressing.
512 frame_access_state()->SetFrameAccessToFP();
513 int const num_parameters = MiscField::decode(instr->opcode());
514 __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
515 break;
516 }
517 case kArchPrepareTailCall:
518 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
519 break;
520 case kArchCallCFunction: {
521 int const num_parameters = MiscField::decode(instr->opcode());
522 if (HasImmediateInput(instr, 0)) {
523 ExternalReference ref = i.InputExternalReference(0);
524 __ CallCFunction(ref, num_parameters);
525 } else {
526 Register func = i.InputRegister(0);
527 __ CallCFunction(func, num_parameters);
528 }
529 frame_access_state()->SetFrameAccessToDefault();
530 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 break;
532 }
533 case kArchJmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400534 AssembleArchJump(i.InputRpo(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 case kArchLookupSwitch:
537 AssembleArchLookupSwitch(instr);
538 break;
539 case kArchTableSwitch:
540 AssembleArchTableSwitch(instr);
541 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 case kArchThrowTerminator:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 // don't emit code for nops.
545 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 case kArchDeoptimize: {
547 int deopt_state_id =
548 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
549 Deoptimizer::BailoutType bailout_type =
550 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochc5610432016-08-08 18:44:38 +0100551 CodeGenResult result =
552 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
553 if (result != kSuccess) return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 break;
555 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 case kArchRet:
557 AssembleReturn();
558 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559 case kArchStackPointer:
560 __ mov(i.OutputRegister(), esp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 case kArchFramePointer:
563 __ mov(i.OutputRegister(), ebp);
564 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100566 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100567 __ mov(i.OutputRegister(), Operand(ebp, 0));
568 } else {
569 __ mov(i.OutputRegister(), ebp);
570 }
571 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400572 case kArchTruncateDoubleToI: {
573 auto result = i.OutputRegister();
574 auto input = i.InputDoubleRegister(0);
575 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
576 __ cvttsd2si(result, Operand(input));
577 __ cmp(result, 1);
578 __ j(overflow, ool->entry());
579 __ bind(ool->exit());
580 break;
581 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000582 case kArchStoreWithWriteBarrier: {
583 RecordWriteMode mode =
584 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
585 Register object = i.InputRegister(0);
586 size_t index = 0;
587 Operand operand = i.MemoryOperand(&index);
588 Register value = i.InputRegister(index);
589 Register scratch0 = i.TempRegister(0);
590 Register scratch1 = i.TempRegister(1);
591 auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
592 scratch0, scratch1, mode);
593 __ mov(operand, value);
594 __ CheckPageFlag(object, scratch0,
595 MemoryChunk::kPointersFromHereAreInterestingMask,
596 not_zero, ool->entry());
597 __ bind(ool->exit());
598 break;
599 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100600 case kArchStackSlot: {
601 FrameOffset offset =
602 frame_access_state()->GetFrameOffset(i.InputInt32(0));
603 Register base;
604 if (offset.from_stack_pointer()) {
605 base = esp;
606 } else {
607 base = ebp;
608 }
609 __ lea(i.OutputRegister(), Operand(base, offset.offset()));
610 break;
611 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 case kIA32Add:
613 if (HasImmediateInput(instr, 1)) {
614 __ add(i.InputOperand(0), i.InputImmediate(1));
615 } else {
616 __ add(i.InputRegister(0), i.InputOperand(1));
617 }
618 break;
619 case kIA32And:
620 if (HasImmediateInput(instr, 1)) {
621 __ and_(i.InputOperand(0), i.InputImmediate(1));
622 } else {
623 __ and_(i.InputRegister(0), i.InputOperand(1));
624 }
625 break;
626 case kIA32Cmp:
Ben Murdochda12d292016-06-02 14:46:10 +0100627 ASSEMBLE_COMPARE(cmp);
628 break;
629 case kIA32Cmp16:
630 ASSEMBLE_COMPARE(cmpw);
631 break;
632 case kIA32Cmp8:
633 ASSEMBLE_COMPARE(cmpb);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 break;
635 case kIA32Test:
Ben Murdochda12d292016-06-02 14:46:10 +0100636 ASSEMBLE_COMPARE(test);
637 break;
638 case kIA32Test16:
639 ASSEMBLE_COMPARE(test_w);
640 break;
641 case kIA32Test8:
642 ASSEMBLE_COMPARE(test_b);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643 break;
644 case kIA32Imul:
645 if (HasImmediateInput(instr, 1)) {
646 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
647 } else {
648 __ imul(i.OutputRegister(), i.InputOperand(1));
649 }
650 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400651 case kIA32ImulHigh:
652 __ imul(i.InputRegister(1));
653 break;
654 case kIA32UmulHigh:
655 __ mul(i.InputRegister(1));
656 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 case kIA32Idiv:
658 __ cdq();
659 __ idiv(i.InputOperand(1));
660 break;
661 case kIA32Udiv:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400662 __ Move(edx, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663 __ div(i.InputOperand(1));
664 break;
665 case kIA32Not:
666 __ not_(i.OutputOperand());
667 break;
668 case kIA32Neg:
669 __ neg(i.OutputOperand());
670 break;
671 case kIA32Or:
672 if (HasImmediateInput(instr, 1)) {
673 __ or_(i.InputOperand(0), i.InputImmediate(1));
674 } else {
675 __ or_(i.InputRegister(0), i.InputOperand(1));
676 }
677 break;
678 case kIA32Xor:
679 if (HasImmediateInput(instr, 1)) {
680 __ xor_(i.InputOperand(0), i.InputImmediate(1));
681 } else {
682 __ xor_(i.InputRegister(0), i.InputOperand(1));
683 }
684 break;
685 case kIA32Sub:
686 if (HasImmediateInput(instr, 1)) {
687 __ sub(i.InputOperand(0), i.InputImmediate(1));
688 } else {
689 __ sub(i.InputRegister(0), i.InputOperand(1));
690 }
691 break;
692 case kIA32Shl:
693 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400694 __ shl(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000695 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400696 __ shl_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 }
698 break;
699 case kIA32Shr:
700 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400701 __ shr(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000702 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400703 __ shr_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000704 }
705 break;
706 case kIA32Sar:
707 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400708 __ sar(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400710 __ sar_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 }
712 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100713 case kIA32AddPair: {
714 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
715 // i.InputRegister(1) ... left high word.
716 // i.InputRegister(2) ... right low word.
717 // i.InputRegister(3) ... right high word.
718 bool use_temp = false;
719 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
720 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
721 // We cannot write to the output register directly, because it would
722 // overwrite an input for adc. We have to use the temp register.
723 use_temp = true;
724 __ Move(i.TempRegister(0), i.InputRegister(0));
725 __ add(i.TempRegister(0), i.InputRegister(2));
726 } else {
727 __ add(i.OutputRegister(0), i.InputRegister(2));
728 }
729 __ adc(i.InputRegister(1), Operand(i.InputRegister(3)));
730 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
731 __ Move(i.OutputRegister(1), i.InputRegister(1));
732 }
733 if (use_temp) {
734 __ Move(i.OutputRegister(0), i.TempRegister(0));
735 }
736 break;
737 }
738 case kIA32SubPair: {
739 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
740 // i.InputRegister(1) ... left high word.
741 // i.InputRegister(2) ... right low word.
742 // i.InputRegister(3) ... right high word.
743 bool use_temp = false;
744 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
745 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
746 // We cannot write to the output register directly, because it would
747 // overwrite an input for adc. We have to use the temp register.
748 use_temp = true;
749 __ Move(i.TempRegister(0), i.InputRegister(0));
750 __ sub(i.TempRegister(0), i.InputRegister(2));
751 } else {
752 __ sub(i.OutputRegister(0), i.InputRegister(2));
753 }
754 __ sbb(i.InputRegister(1), Operand(i.InputRegister(3)));
755 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
756 __ Move(i.OutputRegister(1), i.InputRegister(1));
757 }
758 if (use_temp) {
759 __ Move(i.OutputRegister(0), i.TempRegister(0));
760 }
761 break;
762 }
763 case kIA32MulPair: {
764 __ imul(i.OutputRegister(1), i.InputOperand(0));
765 __ mov(i.TempRegister(0), i.InputOperand(1));
766 __ imul(i.TempRegister(0), i.InputOperand(2));
767 __ add(i.OutputRegister(1), i.TempRegister(0));
768 __ mov(i.OutputRegister(0), i.InputOperand(0));
769 // Multiplies the low words and stores them in eax and edx.
770 __ mul(i.InputRegister(2));
771 __ add(i.OutputRegister(1), i.TempRegister(0));
772
773 break;
774 }
775 case kIA32ShlPair:
776 if (HasImmediateInput(instr, 2)) {
777 __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
778 } else {
779 // Shift has been loaded into CL by the register allocator.
780 __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0));
781 }
782 break;
783 case kIA32ShrPair:
784 if (HasImmediateInput(instr, 2)) {
785 __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
786 } else {
787 // Shift has been loaded into CL by the register allocator.
788 __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0));
789 }
790 break;
791 case kIA32SarPair:
792 if (HasImmediateInput(instr, 2)) {
793 __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
794 } else {
795 // Shift has been loaded into CL by the register allocator.
796 __ SarPair_cl(i.InputRegister(1), i.InputRegister(0));
797 }
798 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 case kIA32Ror:
800 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400801 __ ror(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400803 __ ror_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 }
805 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 case kIA32Lzcnt:
807 __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
808 break;
809 case kIA32Tzcnt:
810 __ Tzcnt(i.OutputRegister(), i.InputOperand(0));
811 break;
812 case kIA32Popcnt:
813 __ Popcnt(i.OutputRegister(), i.InputOperand(0));
814 break;
815 case kSSEFloat32Cmp:
816 __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
817 break;
818 case kSSEFloat32Add:
819 __ addss(i.InputDoubleRegister(0), i.InputOperand(1));
820 break;
821 case kSSEFloat32Sub:
822 __ subss(i.InputDoubleRegister(0), i.InputOperand(1));
823 break;
824 case kSSEFloat32Mul:
825 __ mulss(i.InputDoubleRegister(0), i.InputOperand(1));
826 break;
827 case kSSEFloat32Div:
828 __ divss(i.InputDoubleRegister(0), i.InputOperand(1));
829 // Don't delete this mov. It may improve performance on some CPUs,
830 // when there is a (v)mulss depending on the result.
831 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
832 break;
833 case kSSEFloat32Max:
834 __ maxss(i.InputDoubleRegister(0), i.InputOperand(1));
835 break;
836 case kSSEFloat32Min:
837 __ minss(i.InputDoubleRegister(0), i.InputOperand(1));
838 break;
839 case kSSEFloat32Sqrt:
840 __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
841 break;
842 case kSSEFloat32Abs: {
843 // TODO(bmeurer): Use 128-bit constants.
844 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
845 __ psrlq(kScratchDoubleReg, 33);
846 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
847 break;
848 }
849 case kSSEFloat32Neg: {
850 // TODO(bmeurer): Use 128-bit constants.
851 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
852 __ psllq(kScratchDoubleReg, 31);
853 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
854 break;
855 }
856 case kSSEFloat32Round: {
857 CpuFeatureScope sse_scope(masm(), SSE4_1);
858 RoundingMode const mode =
859 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
860 __ roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
861 break;
862 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 case kSSEFloat64Cmp:
864 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
865 break;
866 case kSSEFloat64Add:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400867 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000868 break;
869 case kSSEFloat64Sub:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400870 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871 break;
872 case kSSEFloat64Mul:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400873 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874 break;
875 case kSSEFloat64Div:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400876 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000877 // Don't delete this mov. It may improve performance on some CPUs,
878 // when there is a (v)mulsd depending on the result.
879 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
880 break;
881 case kSSEFloat64Max:
882 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
883 break;
884 case kSSEFloat64Min:
885 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000886 break;
887 case kSSEFloat64Mod: {
888 // TODO(dcarney): alignment is wrong.
889 __ sub(esp, Immediate(kDoubleSize));
890 // Move values to st(0) and st(1).
891 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
892 __ fld_d(Operand(esp, 0));
893 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
894 __ fld_d(Operand(esp, 0));
895 // Loop while fprem isn't done.
896 Label mod_loop;
897 __ bind(&mod_loop);
898 // This instructions traps on all kinds inputs, but we are assuming the
899 // floating point control word is set to ignore them all.
900 __ fprem();
901 // The following 2 instruction implicitly use eax.
902 __ fnstsw_ax();
903 __ sahf();
904 __ j(parity_even, &mod_loop);
905 // Move output to stack and clean up.
906 __ fstp(1);
907 __ fstp_d(Operand(esp, 0));
908 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
909 __ add(esp, Immediate(kDoubleSize));
910 break;
911 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 case kSSEFloat64Abs: {
913 // TODO(bmeurer): Use 128-bit constants.
914 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
915 __ psrlq(kScratchDoubleReg, 1);
916 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
917 break;
918 }
919 case kSSEFloat64Neg: {
920 // TODO(bmeurer): Use 128-bit constants.
921 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
922 __ psllq(kScratchDoubleReg, 63);
923 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
924 break;
925 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926 case kSSEFloat64Sqrt:
927 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
928 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000929 case kSSEFloat64Round: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400930 CpuFeatureScope sse_scope(masm(), SSE4_1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 RoundingMode const mode =
932 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
933 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400934 break;
935 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 case kSSEFloat32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400937 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
938 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 case kSSEFloat64ToFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400940 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
941 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100942 case kSSEFloat32ToInt32:
943 __ cvttss2si(i.OutputRegister(), i.InputOperand(0));
944 break;
945 case kSSEFloat32ToUint32: {
946 Label success;
947 __ cvttss2si(i.OutputRegister(), i.InputOperand(0));
948 __ test(i.OutputRegister(), i.OutputRegister());
949 __ j(positive, &success);
950 __ Move(kScratchDoubleReg, static_cast<float>(INT32_MIN));
951 __ addss(kScratchDoubleReg, i.InputOperand(0));
952 __ cvttss2si(i.OutputRegister(), kScratchDoubleReg);
953 __ or_(i.OutputRegister(), Immediate(0x80000000));
954 __ bind(&success);
955 break;
956 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000957 case kSSEFloat64ToInt32:
958 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
959 break;
960 case kSSEFloat64ToUint32: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000961 __ Move(kScratchDoubleReg, -2147483648.0);
962 __ addsd(kScratchDoubleReg, i.InputOperand(0));
963 __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964 __ add(i.OutputRegister(), Immediate(0x80000000));
965 break;
966 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100967 case kSSEInt32ToFloat32:
968 __ cvtsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
969 break;
970 case kSSEUint32ToFloat32: {
971 Register scratch0 = i.TempRegister(0);
972 Register scratch1 = i.TempRegister(1);
973 __ mov(scratch0, i.InputOperand(0));
974 __ Cvtui2ss(i.OutputDoubleRegister(), scratch0, scratch1);
975 break;
976 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000977 case kSSEInt32ToFloat64:
978 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
979 break;
980 case kSSEUint32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400981 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 case kSSEFloat64ExtractLowWord32:
Ben Murdochc5610432016-08-08 18:44:38 +0100984 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 __ mov(i.OutputRegister(), i.InputOperand(0));
986 } else {
987 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
988 }
989 break;
990 case kSSEFloat64ExtractHighWord32:
Ben Murdochc5610432016-08-08 18:44:38 +0100991 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000992 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
993 } else {
994 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
995 }
996 break;
997 case kSSEFloat64InsertLowWord32:
998 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
999 break;
1000 case kSSEFloat64InsertHighWord32:
1001 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
1002 break;
1003 case kSSEFloat64LoadLowWord32:
1004 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
1005 break;
1006 case kAVXFloat32Add: {
1007 CpuFeatureScope avx_scope(masm(), AVX);
1008 __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1009 i.InputOperand(1));
1010 break;
1011 }
1012 case kAVXFloat32Sub: {
1013 CpuFeatureScope avx_scope(masm(), AVX);
1014 __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1015 i.InputOperand(1));
1016 break;
1017 }
1018 case kAVXFloat32Mul: {
1019 CpuFeatureScope avx_scope(masm(), AVX);
1020 __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1021 i.InputOperand(1));
1022 break;
1023 }
1024 case kAVXFloat32Div: {
1025 CpuFeatureScope avx_scope(masm(), AVX);
1026 __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1027 i.InputOperand(1));
1028 // Don't delete this mov. It may improve performance on some CPUs,
1029 // when there is a (v)mulss depending on the result.
1030 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1031 break;
1032 }
1033 case kAVXFloat32Max: {
1034 CpuFeatureScope avx_scope(masm(), AVX);
1035 __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1036 i.InputOperand(1));
1037 break;
1038 }
1039 case kAVXFloat32Min: {
1040 CpuFeatureScope avx_scope(masm(), AVX);
1041 __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1042 i.InputOperand(1));
1043 break;
1044 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001045 case kAVXFloat64Add: {
1046 CpuFeatureScope avx_scope(masm(), AVX);
1047 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1048 i.InputOperand(1));
1049 break;
1050 }
1051 case kAVXFloat64Sub: {
1052 CpuFeatureScope avx_scope(masm(), AVX);
1053 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1054 i.InputOperand(1));
1055 break;
1056 }
1057 case kAVXFloat64Mul: {
1058 CpuFeatureScope avx_scope(masm(), AVX);
1059 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1060 i.InputOperand(1));
1061 break;
1062 }
1063 case kAVXFloat64Div: {
1064 CpuFeatureScope avx_scope(masm(), AVX);
1065 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1066 i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 // Don't delete this mov. It may improve performance on some CPUs,
1068 // when there is a (v)mulsd depending on the result.
1069 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1070 break;
1071 }
1072 case kAVXFloat64Max: {
1073 CpuFeatureScope avx_scope(masm(), AVX);
1074 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1075 i.InputOperand(1));
1076 break;
1077 }
1078 case kAVXFloat64Min: {
1079 CpuFeatureScope avx_scope(masm(), AVX);
1080 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1081 i.InputOperand(1));
1082 break;
1083 }
1084 case kAVXFloat32Abs: {
1085 // TODO(bmeurer): Use RIP relative 128-bit constants.
1086 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1087 __ psrlq(kScratchDoubleReg, 33);
1088 CpuFeatureScope avx_scope(masm(), AVX);
1089 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1090 break;
1091 }
1092 case kAVXFloat32Neg: {
1093 // TODO(bmeurer): Use RIP relative 128-bit constants.
1094 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1095 __ psllq(kScratchDoubleReg, 31);
1096 CpuFeatureScope avx_scope(masm(), AVX);
1097 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1098 break;
1099 }
1100 case kAVXFloat64Abs: {
1101 // TODO(bmeurer): Use RIP relative 128-bit constants.
1102 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1103 __ psrlq(kScratchDoubleReg, 1);
1104 CpuFeatureScope avx_scope(masm(), AVX);
1105 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1106 break;
1107 }
1108 case kAVXFloat64Neg: {
1109 // TODO(bmeurer): Use RIP relative 128-bit constants.
1110 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1111 __ psllq(kScratchDoubleReg, 63);
1112 CpuFeatureScope avx_scope(masm(), AVX);
1113 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001114 break;
1115 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116 case kIA32Movsxbl:
1117 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
1118 break;
1119 case kIA32Movzxbl:
1120 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
1121 break;
1122 case kIA32Movb: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001123 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001124 Operand operand = i.MemoryOperand(&index);
1125 if (HasImmediateInput(instr, index)) {
1126 __ mov_b(operand, i.InputInt8(index));
1127 } else {
1128 __ mov_b(operand, i.InputRegister(index));
1129 }
1130 break;
1131 }
1132 case kIA32Movsxwl:
1133 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
1134 break;
1135 case kIA32Movzxwl:
1136 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
1137 break;
1138 case kIA32Movw: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001139 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 Operand operand = i.MemoryOperand(&index);
1141 if (HasImmediateInput(instr, index)) {
1142 __ mov_w(operand, i.InputInt16(index));
1143 } else {
1144 __ mov_w(operand, i.InputRegister(index));
1145 }
1146 break;
1147 }
1148 case kIA32Movl:
1149 if (instr->HasOutput()) {
1150 __ mov(i.OutputRegister(), i.MemoryOperand());
1151 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 Operand operand = i.MemoryOperand(&index);
1154 if (HasImmediateInput(instr, index)) {
1155 __ mov(operand, i.InputImmediate(index));
1156 } else {
1157 __ mov(operand, i.InputRegister(index));
1158 }
1159 }
1160 break;
1161 case kIA32Movsd:
1162 if (instr->HasOutput()) {
1163 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
1164 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 Operand operand = i.MemoryOperand(&index);
1167 __ movsd(operand, i.InputDoubleRegister(index));
1168 }
1169 break;
1170 case kIA32Movss:
1171 if (instr->HasOutput()) {
1172 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001173 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175 Operand operand = i.MemoryOperand(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001176 __ movss(operand, i.InputDoubleRegister(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 }
1178 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001179 case kIA32BitcastFI:
Ben Murdochc5610432016-08-08 18:44:38 +01001180 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001181 __ mov(i.OutputRegister(), i.InputOperand(0));
1182 } else {
1183 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
1184 }
1185 break;
1186 case kIA32BitcastIF:
1187 if (instr->InputAt(0)->IsRegister()) {
1188 __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
1189 } else {
1190 __ movss(i.OutputDoubleRegister(), i.InputOperand(0));
1191 }
1192 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001193 case kIA32Lea: {
1194 AddressingMode mode = AddressingModeField::decode(instr->opcode());
1195 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1196 // and addressing mode just happens to work out. The "addl"/"subl" forms
1197 // in these cases are faster based on measurements.
1198 if (mode == kMode_MI) {
1199 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
1200 } else if (i.InputRegister(0).is(i.OutputRegister())) {
1201 if (mode == kMode_MRI) {
1202 int32_t constant_summand = i.InputInt32(1);
1203 if (constant_summand > 0) {
1204 __ add(i.OutputRegister(), Immediate(constant_summand));
1205 } else if (constant_summand < 0) {
1206 __ sub(i.OutputRegister(), Immediate(-constant_summand));
1207 }
1208 } else if (mode == kMode_MR1) {
1209 if (i.InputRegister(1).is(i.OutputRegister())) {
1210 __ shl(i.OutputRegister(), 1);
1211 } else {
1212 __ lea(i.OutputRegister(), i.MemoryOperand());
1213 }
1214 } else if (mode == kMode_M2) {
1215 __ shl(i.OutputRegister(), 1);
1216 } else if (mode == kMode_M4) {
1217 __ shl(i.OutputRegister(), 2);
1218 } else if (mode == kMode_M8) {
1219 __ shl(i.OutputRegister(), 3);
1220 } else {
1221 __ lea(i.OutputRegister(), i.MemoryOperand());
1222 }
1223 } else {
1224 __ lea(i.OutputRegister(), i.MemoryOperand());
1225 }
1226 break;
1227 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 case kIA32PushFloat32:
Ben Murdochc5610432016-08-08 18:44:38 +01001229 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 __ sub(esp, Immediate(kDoubleSize));
1231 __ movss(Operand(esp, 0), i.InputDoubleRegister(0));
1232 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1233 } else if (HasImmediateInput(instr, 0)) {
1234 __ Move(kScratchDoubleReg, i.InputDouble(0));
1235 __ sub(esp, Immediate(kDoubleSize));
1236 __ movss(Operand(esp, 0), kScratchDoubleReg);
1237 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1240 __ sub(esp, Immediate(kDoubleSize));
1241 __ movss(Operand(esp, 0), kScratchDoubleReg);
1242 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 }
1244 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245 case kIA32PushFloat64:
Ben Murdochc5610432016-08-08 18:44:38 +01001246 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001247 __ sub(esp, Immediate(kDoubleSize));
1248 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
1249 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1250 } else if (HasImmediateInput(instr, 0)) {
1251 __ Move(kScratchDoubleReg, i.InputDouble(0));
1252 __ sub(esp, Immediate(kDoubleSize));
1253 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1254 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1255 } else {
1256 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1257 __ sub(esp, Immediate(kDoubleSize));
1258 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1259 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1260 }
1261 break;
1262 case kIA32Push:
Ben Murdochc5610432016-08-08 18:44:38 +01001263 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 __ sub(esp, Immediate(kDoubleSize));
1265 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
1266 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1267 } else if (HasImmediateInput(instr, 0)) {
1268 __ push(i.InputImmediate(0));
1269 frame_access_state()->IncreaseSPDelta(1);
1270 } else {
1271 __ push(i.InputOperand(0));
1272 frame_access_state()->IncreaseSPDelta(1);
1273 }
1274 break;
1275 case kIA32Poke: {
1276 int const slot = MiscField::decode(instr->opcode());
1277 if (HasImmediateInput(instr, 0)) {
1278 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
1279 } else {
1280 __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0));
1281 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282 break;
1283 }
Ben Murdochc5610432016-08-08 18:44:38 +01001284 case kIA32Xchgb: {
1285 size_t index = 0;
1286 Operand operand = i.MemoryOperand(&index);
1287 __ xchg_b(i.InputRegister(index), operand);
1288 break;
1289 }
1290 case kIA32Xchgw: {
1291 size_t index = 0;
1292 Operand operand = i.MemoryOperand(&index);
1293 __ xchg_w(i.InputRegister(index), operand);
1294 break;
1295 }
1296 case kIA32Xchgl: {
1297 size_t index = 0;
1298 Operand operand = i.MemoryOperand(&index);
1299 __ xchg(i.InputRegister(index), operand);
1300 break;
1301 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001302 case kCheckedLoadInt8:
1303 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
1304 break;
1305 case kCheckedLoadUint8:
1306 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
1307 break;
1308 case kCheckedLoadInt16:
1309 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
1310 break;
1311 case kCheckedLoadUint16:
1312 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
1313 break;
1314 case kCheckedLoadWord32:
1315 ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
1316 break;
1317 case kCheckedLoadFloat32:
1318 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
1319 break;
1320 case kCheckedLoadFloat64:
1321 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
1322 break;
1323 case kCheckedStoreWord8:
1324 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
1325 break;
1326 case kCheckedStoreWord16:
1327 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
1328 break;
1329 case kCheckedStoreWord32:
1330 ASSEMBLE_CHECKED_STORE_INTEGER(mov);
1331 break;
1332 case kCheckedStoreFloat32:
1333 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
1334 break;
1335 case kCheckedStoreFloat64:
1336 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
1337 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001338 case kIA32StackCheck: {
1339 ExternalReference const stack_limit =
1340 ExternalReference::address_of_stack_limit(isolate());
1341 __ cmp(esp, Operand::StaticVariable(stack_limit));
1342 break;
1343 }
1344 case kCheckedLoadWord64:
1345 case kCheckedStoreWord64:
1346 UNREACHABLE(); // currently unsupported checked int64 load/store.
1347 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001348 case kAtomicLoadInt8:
1349 case kAtomicLoadUint8:
1350 case kAtomicLoadInt16:
1351 case kAtomicLoadUint16:
1352 case kAtomicLoadWord32:
1353 case kAtomicStoreWord8:
1354 case kAtomicStoreWord16:
1355 case kAtomicStoreWord32:
1356 UNREACHABLE(); // Won't be generated by instruction selector.
1357 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 }
Ben Murdochc5610432016-08-08 18:44:38 +01001359 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001360} // NOLINT(readability/fn_size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361
1362
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001363// Assembles a branch after an instruction.
1364void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365 IA32OperandConverter i(this, instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001366 Label::Distance flabel_distance =
1367 branch->fallthru ? Label::kNear : Label::kFar;
1368 Label* tlabel = branch->true_label;
1369 Label* flabel = branch->false_label;
1370 switch (branch->condition) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001371 case kUnorderedEqual:
1372 __ j(parity_even, flabel, flabel_distance);
1373 // Fall through.
1374 case kEqual:
1375 __ j(equal, tlabel);
1376 break;
1377 case kUnorderedNotEqual:
1378 __ j(parity_even, tlabel);
1379 // Fall through.
1380 case kNotEqual:
1381 __ j(not_equal, tlabel);
1382 break;
1383 case kSignedLessThan:
1384 __ j(less, tlabel);
1385 break;
1386 case kSignedGreaterThanOrEqual:
1387 __ j(greater_equal, tlabel);
1388 break;
1389 case kSignedLessThanOrEqual:
1390 __ j(less_equal, tlabel);
1391 break;
1392 case kSignedGreaterThan:
1393 __ j(greater, tlabel);
1394 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 case kUnsignedLessThan:
1396 __ j(below, tlabel);
1397 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 case kUnsignedGreaterThanOrEqual:
1399 __ j(above_equal, tlabel);
1400 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401 case kUnsignedLessThanOrEqual:
1402 __ j(below_equal, tlabel);
1403 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001404 case kUnsignedGreaterThan:
1405 __ j(above, tlabel);
1406 break;
1407 case kOverflow:
1408 __ j(overflow, tlabel);
1409 break;
1410 case kNotOverflow:
1411 __ j(no_overflow, tlabel);
1412 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 default:
1414 UNREACHABLE();
1415 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001416 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001417 // Add a jump if not falling through to the next block.
1418 if (!branch->fallthru) __ jmp(flabel);
1419}
1420
1421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001423 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001424}
1425
1426
1427// Assembles boolean materializations after an instruction.
1428void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1429 FlagsCondition condition) {
1430 IA32OperandConverter i(this, instr);
1431 Label done;
1432
1433 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1434 // last output of the instruction.
1435 Label check;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001436 DCHECK_NE(0u, instr->OutputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 Register reg = i.OutputRegister(instr->OutputCount() - 1);
1438 Condition cc = no_condition;
1439 switch (condition) {
1440 case kUnorderedEqual:
1441 __ j(parity_odd, &check, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001442 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 __ jmp(&done, Label::kNear);
1444 // Fall through.
1445 case kEqual:
1446 cc = equal;
1447 break;
1448 case kUnorderedNotEqual:
1449 __ j(parity_odd, &check, Label::kNear);
1450 __ mov(reg, Immediate(1));
1451 __ jmp(&done, Label::kNear);
1452 // Fall through.
1453 case kNotEqual:
1454 cc = not_equal;
1455 break;
1456 case kSignedLessThan:
1457 cc = less;
1458 break;
1459 case kSignedGreaterThanOrEqual:
1460 cc = greater_equal;
1461 break;
1462 case kSignedLessThanOrEqual:
1463 cc = less_equal;
1464 break;
1465 case kSignedGreaterThan:
1466 cc = greater;
1467 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468 case kUnsignedLessThan:
1469 cc = below;
1470 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001471 case kUnsignedGreaterThanOrEqual:
1472 cc = above_equal;
1473 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001474 case kUnsignedLessThanOrEqual:
1475 cc = below_equal;
1476 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 case kUnsignedGreaterThan:
1478 cc = above;
1479 break;
1480 case kOverflow:
1481 cc = overflow;
1482 break;
1483 case kNotOverflow:
1484 cc = no_overflow;
1485 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 default:
1487 UNREACHABLE();
1488 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489 }
1490 __ bind(&check);
1491 if (reg.is_byte_register()) {
1492 // setcc for byte registers (al, bl, cl, dl).
1493 __ setcc(cc, reg);
1494 __ movzx_b(reg, reg);
1495 } else {
1496 // Emit a branch to set a register to either 1 or 0.
1497 Label set;
1498 __ j(cc, &set, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001499 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001500 __ jmp(&done, Label::kNear);
1501 __ bind(&set);
1502 __ mov(reg, Immediate(1));
1503 }
1504 __ bind(&done);
1505}
1506
1507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1509 IA32OperandConverter i(this, instr);
1510 Register input = i.InputRegister(0);
1511 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1512 __ cmp(input, Immediate(i.InputInt32(index + 0)));
1513 __ j(equal, GetLabel(i.InputRpo(index + 1)));
1514 }
1515 AssembleArchJump(i.InputRpo(1));
1516}
1517
1518
1519void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1520 IA32OperandConverter i(this, instr);
1521 Register input = i.InputRegister(0);
1522 size_t const case_count = instr->InputCount() - 2;
1523 Label** cases = zone()->NewArray<Label*>(case_count);
1524 for (size_t index = 0; index < case_count; ++index) {
1525 cases[index] = GetLabel(i.InputRpo(index + 2));
1526 }
1527 Label* const table = AddJumpTable(cases, case_count);
1528 __ cmp(input, Immediate(case_count));
1529 __ j(above_equal, GetLabel(i.InputRpo(1)));
1530 __ jmp(Operand::JumpTable(input, times_4, table));
1531}
1532
Ben Murdochc5610432016-08-08 18:44:38 +01001533CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001535 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 isolate(), deoptimization_id, bailout_type);
Ben Murdochc5610432016-08-08 18:44:38 +01001537 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001538 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochc5610432016-08-08 18:44:38 +01001539 return kSuccess;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001540}
1541
1542
1543// The calling convention for JSFunctions on IA32 passes arguments on the
1544// stack and the JSFunction and context in EDI and ESI, respectively, thus
1545// the steps of the call look as follows:
1546
1547// --{ before the call instruction }--------------------------------------------
1548// | caller frame |
1549// ^ esp ^ ebp
1550
1551// --{ push arguments and setup ESI, EDI }--------------------------------------
1552// | args + receiver | caller frame |
1553// ^ esp ^ ebp
1554// [edi = JSFunction, esi = context]
1555
1556// --{ call [edi + kCodeEntryOffset] }------------------------------------------
1557// | RET | args + receiver | caller frame |
1558// ^ esp ^ ebp
1559
1560// =={ prologue of called function }============================================
1561// --{ push ebp }---------------------------------------------------------------
1562// | FP | RET | args + receiver | caller frame |
1563// ^ esp ^ ebp
1564
1565// --{ mov ebp, esp }-----------------------------------------------------------
1566// | FP | RET | args + receiver | caller frame |
1567// ^ ebp,esp
1568
1569// --{ push esi }---------------------------------------------------------------
1570// | CTX | FP | RET | args + receiver | caller frame |
1571// ^esp ^ ebp
1572
1573// --{ push edi }---------------------------------------------------------------
1574// | FNC | CTX | FP | RET | args + receiver | caller frame |
1575// ^esp ^ ebp
1576
1577// --{ subi esp, #N }-----------------------------------------------------------
1578// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
1579// ^esp ^ ebp
1580
1581// =={ body of called function }================================================
1582
1583// =={ epilogue of called function }============================================
1584// --{ mov esp, ebp }-----------------------------------------------------------
1585// | FP | RET | args + receiver | caller frame |
1586// ^ esp,ebp
1587
1588// --{ pop ebp }-----------------------------------------------------------
1589// | | RET | args + receiver | caller frame |
1590// ^ esp ^ ebp
1591
1592// --{ ret #A+1 }-----------------------------------------------------------
1593// | | caller frame |
1594// ^ esp ^ ebp
1595
1596
1597// Runtime function calls are accomplished by doing a stub call to the
1598// CEntryStub (a real code object). On IA32 passes arguments on the
1599// stack, the number of arguments in EAX, the address of the runtime function
1600// in EBX, and the context in ESI.
1601
1602// --{ before the call instruction }--------------------------------------------
1603// | caller frame |
1604// ^ esp ^ ebp
1605
1606// --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
1607// | args + receiver | caller frame |
1608// ^ esp ^ ebp
1609// [eax = #args, ebx = runtime function, esi = context]
1610
1611// --{ call #CEntryStub }-------------------------------------------------------
1612// | RET | args + receiver | caller frame |
1613// ^ esp ^ ebp
1614
1615// =={ body of runtime function }===============================================
1616
1617// --{ runtime returns }--------------------------------------------------------
1618// | caller frame |
1619// ^ esp ^ ebp
1620
1621// Other custom linkages (e.g. for calling directly into and out of C++) may
1622// need to save callee-saved registers on the stack, which is done in the
1623// function prologue of generated code.
1624
1625// --{ before the call instruction }--------------------------------------------
1626// | caller frame |
1627// ^ esp ^ ebp
1628
1629// --{ set up arguments in registers on stack }---------------------------------
1630// | args | caller frame |
1631// ^ esp ^ ebp
1632// [r0 = arg0, r1 = arg1, ...]
1633
1634// --{ call code }--------------------------------------------------------------
1635// | RET | args | caller frame |
1636// ^ esp ^ ebp
1637
1638// =={ prologue of called function }============================================
1639// --{ push ebp }---------------------------------------------------------------
1640// | FP | RET | args | caller frame |
1641// ^ esp ^ ebp
1642
1643// --{ mov ebp, esp }-----------------------------------------------------------
1644// | FP | RET | args | caller frame |
1645// ^ ebp,esp
1646
1647// --{ save registers }---------------------------------------------------------
1648// | regs | FP | RET | args | caller frame |
1649// ^ esp ^ ebp
1650
1651// --{ subi esp, #N }-----------------------------------------------------------
1652// | callee frame | regs | FP | RET | args | caller frame |
1653// ^esp ^ ebp
1654
1655// =={ body of called function }================================================
1656
1657// =={ epilogue of called function }============================================
1658// --{ restore registers }------------------------------------------------------
1659// | regs | FP | RET | args | caller frame |
1660// ^ esp ^ ebp
1661
1662// --{ mov esp, ebp }-----------------------------------------------------------
1663// | FP | RET | args | caller frame |
1664// ^ esp,ebp
1665
1666// --{ pop ebp }----------------------------------------------------------------
1667// | RET | args | caller frame |
1668// ^ esp ^ ebp
1669
Ben Murdochc5610432016-08-08 18:44:38 +01001670void CodeGenerator::FinishFrame(Frame* frame) {
1671 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1672 const RegList saves = descriptor->CalleeSavedRegisters();
1673 if (saves != 0) { // Save callee-saved registers.
1674 DCHECK(!info()->is_osr());
1675 int pushed = 0;
1676 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1677 if (!((1 << i) & saves)) continue;
1678 ++pushed;
1679 }
1680 frame->AllocateSavedCalleeRegisterSlots(pushed);
1681 }
1682}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001683
Ben Murdochc5610432016-08-08 18:44:38 +01001684void CodeGenerator::AssembleConstructFrame() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01001686 if (frame_access_state()->has_frame()) {
1687 if (descriptor->IsCFunctionCall()) {
1688 __ push(ebp);
1689 __ mov(ebp, esp);
1690 } else if (descriptor->IsJSFunctionCall()) {
1691 __ Prologue(this->info()->GeneratePreagedPrologue());
1692 } else {
1693 __ StubPrologue(info()->GetOutputStackFrameType());
1694 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 }
Ben Murdochc5610432016-08-08 18:44:38 +01001696
1697 int shrink_slots = frame()->GetSpillSlotCount();
1698
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001699 if (info()->is_osr()) {
1700 // TurboFan OSR-compiled functions cannot be entered directly.
1701 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1702
1703 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1704 // frame is still on the stack. Optimized code uses OSR values directly from
1705 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1706 // remaining stack slots.
1707 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1708 osr_pc_offset_ = __ pc_offset();
Ben Murdochc5610432016-08-08 18:44:38 +01001709 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001710 }
1711
1712 const RegList saves = descriptor->CalleeSavedRegisters();
Ben Murdochc5610432016-08-08 18:44:38 +01001713 if (shrink_slots > 0) {
1714 __ sub(esp, Immediate(shrink_slots * kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001715 }
1716
1717 if (saves != 0) { // Save callee-saved registers.
1718 DCHECK(!info()->is_osr());
1719 int pushed = 0;
1720 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1721 if (!((1 << i) & saves)) continue;
1722 __ push(Register::from_code(i));
1723 ++pushed;
1724 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 }
1726}
1727
1728
1729void CodeGenerator::AssembleReturn() {
1730 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731
1732 const RegList saves = descriptor->CalleeSavedRegisters();
1733 // Restore registers.
1734 if (saves != 0) {
1735 for (int i = 0; i < Register::kNumRegisters; i++) {
1736 if (!((1 << i) & saves)) continue;
1737 __ pop(Register::from_code(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001738 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739 }
1740
1741 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001742 AssembleDeconstructFrame();
1743 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001744 // Canonicalize JSFunction return sites for now.
1745 if (return_label_.is_bound()) {
1746 __ jmp(&return_label_);
1747 return;
1748 } else {
1749 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01001750 AssembleDeconstructFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001753 size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
1754 // Might need ecx for scratch if pop_size is too big.
1755 DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
1756 __ Ret(static_cast<int>(pop_size), ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001757}
1758
1759
1760void CodeGenerator::AssembleMove(InstructionOperand* source,
1761 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001763 // Dispatch on the source and destination operand kinds. Not all
1764 // combinations are possible.
1765 if (source->IsRegister()) {
1766 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1767 Register src = g.ToRegister(source);
1768 Operand dst = g.ToOperand(destination);
1769 __ mov(dst, src);
1770 } else if (source->IsStackSlot()) {
1771 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1772 Operand src = g.ToOperand(source);
1773 if (destination->IsRegister()) {
1774 Register dst = g.ToRegister(destination);
1775 __ mov(dst, src);
1776 } else {
1777 Operand dst = g.ToOperand(destination);
1778 __ push(src);
1779 __ pop(dst);
1780 }
1781 } else if (source->IsConstant()) {
1782 Constant src_constant = g.ToConstant(source);
1783 if (src_constant.type() == Constant::kHeapObject) {
1784 Handle<HeapObject> src = src_constant.ToHeapObject();
Ben Murdochda12d292016-06-02 14:46:10 +01001785 int slot;
1786 if (IsMaterializableFromFrame(src, &slot)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001787 if (destination->IsRegister()) {
1788 Register dst = g.ToRegister(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01001789 __ mov(dst, g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001790 } else {
1791 DCHECK(destination->IsStackSlot());
1792 Operand dst = g.ToOperand(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01001793 __ push(g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001794 __ pop(dst);
1795 }
1796 } else if (destination->IsRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 Register dst = g.ToRegister(destination);
1798 __ LoadHeapObject(dst, src);
1799 } else {
1800 DCHECK(destination->IsStackSlot());
1801 Operand dst = g.ToOperand(destination);
1802 AllowDeferredHandleDereference embedding_raw_address;
1803 if (isolate()->heap()->InNewSpace(*src)) {
1804 __ PushHeapObject(src);
1805 __ pop(dst);
1806 } else {
1807 __ mov(dst, src);
1808 }
1809 }
1810 } else if (destination->IsRegister()) {
1811 Register dst = g.ToRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001812 __ Move(dst, g.ToImmediate(source));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001813 } else if (destination->IsStackSlot()) {
1814 Operand dst = g.ToOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001815 __ Move(dst, g.ToImmediate(source));
1816 } else if (src_constant.type() == Constant::kFloat32) {
1817 // TODO(turbofan): Can we do better here?
1818 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
Ben Murdochc5610432016-08-08 18:44:38 +01001819 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001820 XMMRegister dst = g.ToDoubleRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001821 __ Move(dst, src);
1822 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001823 DCHECK(destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001824 Operand dst = g.ToOperand(destination);
1825 __ Move(dst, Immediate(src));
1826 }
1827 } else {
1828 DCHECK_EQ(Constant::kFloat64, src_constant.type());
1829 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1830 uint32_t lower = static_cast<uint32_t>(src);
1831 uint32_t upper = static_cast<uint32_t>(src >> 32);
Ben Murdochc5610432016-08-08 18:44:38 +01001832 if (destination->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001833 XMMRegister dst = g.ToDoubleRegister(destination);
1834 __ Move(dst, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001836 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 Operand dst0 = g.ToOperand(destination);
1838 Operand dst1 = g.HighOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001839 __ Move(dst0, Immediate(lower));
1840 __ Move(dst1, Immediate(upper));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841 }
1842 }
Ben Murdochc5610432016-08-08 18:44:38 +01001843 } else if (source->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 XMMRegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001845 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001846 XMMRegister dst = g.ToDoubleRegister(destination);
1847 __ movaps(dst, src);
1848 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001849 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850 Operand dst = g.ToOperand(destination);
1851 __ movsd(dst, src);
1852 }
Ben Murdochc5610432016-08-08 18:44:38 +01001853 } else if (source->IsFPStackSlot()) {
1854 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855 Operand src = g.ToOperand(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001856 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 XMMRegister dst = g.ToDoubleRegister(destination);
1858 __ movsd(dst, src);
1859 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001860 Operand dst = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001861 __ movsd(kScratchDoubleReg, src);
1862 __ movsd(dst, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 }
1864 } else {
1865 UNREACHABLE();
1866 }
1867}
1868
1869
1870void CodeGenerator::AssembleSwap(InstructionOperand* source,
1871 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001872 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001873 // Dispatch on the source and destination operand kinds. Not all
1874 // combinations are possible.
1875 if (source->IsRegister() && destination->IsRegister()) {
1876 // Register-register.
1877 Register src = g.ToRegister(source);
1878 Register dst = g.ToRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001879 __ push(src);
1880 __ mov(src, dst);
1881 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 } else if (source->IsRegister() && destination->IsStackSlot()) {
1883 // Register-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001884 Register src = g.ToRegister(source);
1885 __ push(src);
1886 frame_access_state()->IncreaseSPDelta(1);
1887 Operand dst = g.ToOperand(destination);
1888 __ mov(src, dst);
1889 frame_access_state()->IncreaseSPDelta(-1);
1890 dst = g.ToOperand(destination);
1891 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
1893 // Memory-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001894 Operand dst1 = g.ToOperand(destination);
1895 __ push(dst1);
1896 frame_access_state()->IncreaseSPDelta(1);
1897 Operand src1 = g.ToOperand(source);
1898 __ push(src1);
1899 Operand dst2 = g.ToOperand(destination);
1900 __ pop(dst2);
1901 frame_access_state()->IncreaseSPDelta(-1);
1902 Operand src2 = g.ToOperand(source);
1903 __ pop(src2);
Ben Murdochc5610432016-08-08 18:44:38 +01001904 } else if (source->IsFPRegister() && destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001905 // XMM register-register swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 XMMRegister src = g.ToDoubleRegister(source);
1907 XMMRegister dst = g.ToDoubleRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001908 __ movaps(kScratchDoubleReg, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 __ movaps(src, dst);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001910 __ movaps(dst, kScratchDoubleReg);
Ben Murdochc5610432016-08-08 18:44:38 +01001911 } else if (source->IsFPRegister() && destination->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 // XMM register-memory swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 XMMRegister reg = g.ToDoubleRegister(source);
1914 Operand other = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001915 __ movsd(kScratchDoubleReg, other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 __ movsd(other, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001917 __ movaps(reg, kScratchDoubleReg);
Ben Murdochc5610432016-08-08 18:44:38 +01001918 } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001919 // Double-width memory-to-memory.
1920 Operand src0 = g.ToOperand(source);
1921 Operand src1 = g.HighOperand(source);
1922 Operand dst0 = g.ToOperand(destination);
1923 Operand dst1 = g.HighOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001924 __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register.
1925 __ push(src0); // Then use stack to copy source to destination.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 __ pop(dst0);
1927 __ push(src1);
1928 __ pop(dst1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001929 __ movsd(src0, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001930 } else {
1931 // No other combinations are possible.
1932 UNREACHABLE();
1933 }
1934}
1935
1936
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001937void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1938 for (size_t index = 0; index < target_count; ++index) {
1939 __ dd(targets[index]);
1940 }
1941}
1942
1943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001944void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001945 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1946 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001947 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001948
1949 int space_needed = Deoptimizer::patch_size();
1950 // Ensure that we have enough space after the previous lazy-bailout
1951 // instruction for patching the code here.
1952 int current_pc = masm()->pc_offset();
1953 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1954 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1955 __ Nop(padding_size);
1956 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001957}
1958
1959#undef __
1960
1961} // namespace compiler
1962} // namespace internal
1963} // namespace v8