blob: 6df22f6d5f44d52fad748e958a584be537e27c16 [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 ||
Ben Murdoch61f157c2016-09-16 13:49:30 +010070 constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
Ben Murdochc5610432016-08-08 18:44:38 +010071 constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) {
72 return Immediate(reinterpret_cast<Address>(constant.ToInt32()),
73 constant.rmode());
74 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 switch (constant.type()) {
76 case Constant::kInt32:
77 return Immediate(constant.ToInt32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 case Constant::kFloat32:
79 return Immediate(
80 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 case Constant::kFloat64:
82 return Immediate(
83 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
84 case Constant::kExternalReference:
85 return Immediate(constant.ToExternalReference());
86 case Constant::kHeapObject:
87 return Immediate(constant.ToHeapObject());
88 case Constant::kInt64:
89 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040090 case Constant::kRpoNumber:
91 return Immediate::CodeRelativeOffset(ToLabel(operand));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092 }
93 UNREACHABLE();
94 return Immediate(-1);
95 }
96
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 static size_t NextOffset(size_t* offset) {
98 size_t i = *offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040099 (*offset)++;
100 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 }
102
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400103 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
104 STATIC_ASSERT(0 == static_cast<int>(times_1));
105 STATIC_ASSERT(1 == static_cast<int>(times_2));
106 STATIC_ASSERT(2 == static_cast<int>(times_4));
107 STATIC_ASSERT(3 == static_cast<int>(times_8));
108 int scale = static_cast<int>(mode - one);
109 DCHECK(scale >= 0 && scale < 4);
110 return static_cast<ScaleFactor>(scale);
111 }
112
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 Operand MemoryOperand(size_t* offset) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400114 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
115 switch (mode) {
116 case kMode_MR: {
117 Register base = InputRegister(NextOffset(offset));
118 int32_t disp = 0;
119 return Operand(base, disp);
120 }
121 case kMode_MRI: {
122 Register base = InputRegister(NextOffset(offset));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100123 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
124 return Operand(base, ctant.ToInt32(), ctant.rmode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125 }
126 case kMode_MR1:
127 case kMode_MR2:
128 case kMode_MR4:
129 case kMode_MR8: {
130 Register base = InputRegister(NextOffset(offset));
131 Register index = InputRegister(NextOffset(offset));
132 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
133 int32_t disp = 0;
134 return Operand(base, index, scale, disp);
135 }
136 case kMode_MR1I:
137 case kMode_MR2I:
138 case kMode_MR4I:
139 case kMode_MR8I: {
140 Register base = InputRegister(NextOffset(offset));
141 Register index = InputRegister(NextOffset(offset));
142 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100143 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
144 return Operand(base, index, scale, ctant.ToInt32(), ctant.rmode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400145 }
146 case kMode_M1:
147 case kMode_M2:
148 case kMode_M4:
149 case kMode_M8: {
150 Register index = InputRegister(NextOffset(offset));
151 ScaleFactor scale = ScaleFor(kMode_M1, mode);
152 int32_t disp = 0;
153 return Operand(index, scale, disp);
154 }
155 case kMode_M1I:
156 case kMode_M2I:
157 case kMode_M4I:
158 case kMode_M8I: {
159 Register index = InputRegister(NextOffset(offset));
160 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100161 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
162 return Operand(index, scale, ctant.ToInt32(), ctant.rmode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400163 }
164 case kMode_MI: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100165 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
166 return Operand(ctant.ToInt32(), ctant.rmode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400167 }
168 case kMode_None:
169 UNREACHABLE();
170 return Operand(no_reg, 0);
171 }
172 UNREACHABLE();
173 return Operand(no_reg, 0);
174 }
175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 Operand MemoryOperand(size_t first_input = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 return MemoryOperand(&first_input);
178 }
179};
180
181
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182namespace {
183
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184bool HasImmediateInput(Instruction* instr, size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 return instr->InputAt(index)->IsImmediate();
186}
187
188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 public:
191 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
192 : OutOfLineCode(gen), result_(result) {}
193
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 void Generate() final { __ xor_(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400195
196 private:
197 Register const result_;
198};
199
200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201class OutOfLineLoadFloat final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202 public:
203 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
204 : OutOfLineCode(gen), result_(result) {}
205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 void Generate() final { __ pcmpeqd(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207
208 private:
209 XMMRegister const result_;
210};
211
212
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214 public:
215 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
216 XMMRegister input)
217 : OutOfLineCode(gen), result_(result), input_(input) {}
218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 void Generate() final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400220 __ sub(esp, Immediate(kDoubleSize));
221 __ movsd(MemOperand(esp, 0), input_);
222 __ SlowTruncateToI(result_, esp, 0);
223 __ add(esp, Immediate(kDoubleSize));
224 }
225
226 private:
227 Register const result_;
228 XMMRegister const input_;
229};
230
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231
232class OutOfLineRecordWrite final : public OutOfLineCode {
233 public:
234 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
235 Register value, Register scratch0, Register scratch1,
236 RecordWriteMode mode)
237 : OutOfLineCode(gen),
238 object_(object),
239 operand_(operand),
240 value_(value),
241 scratch0_(scratch0),
242 scratch1_(scratch1),
243 mode_(mode) {}
244
245 void Generate() final {
246 if (mode_ > RecordWriteMode::kValueIsPointer) {
247 __ JumpIfSmi(value_, exit());
248 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100249 __ CheckPageFlag(value_, scratch0_,
250 MemoryChunk::kPointersToHereAreInterestingMask, zero,
251 exit());
252 RememberedSetAction const remembered_set_action =
253 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
254 : OMIT_REMEMBERED_SET;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 SaveFPRegsMode const save_fp_mode =
256 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
257 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100258 remembered_set_action, save_fp_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 __ lea(scratch1_, operand_);
260 __ CallStub(&stub);
261 }
262
263 private:
264 Register const object_;
265 Operand const operand_;
266 Register const value_;
267 Register const scratch0_;
268 Register const scratch1_;
269 RecordWriteMode const mode_;
270};
271
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400272} // namespace
273
274
275#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
276 do { \
277 auto result = i.OutputDoubleRegister(); \
278 auto offset = i.InputRegister(0); \
279 if (instr->InputAt(1)->IsRegister()) { \
280 __ cmp(offset, i.InputRegister(1)); \
281 } else { \
282 __ cmp(offset, i.InputImmediate(1)); \
283 } \
284 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
285 __ j(above_equal, ool->entry()); \
286 __ asm_instr(result, i.MemoryOperand(2)); \
287 __ bind(ool->exit()); \
288 } while (false)
289
290
291#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
292 do { \
293 auto result = i.OutputRegister(); \
294 auto offset = i.InputRegister(0); \
295 if (instr->InputAt(1)->IsRegister()) { \
296 __ cmp(offset, i.InputRegister(1)); \
297 } else { \
298 __ cmp(offset, i.InputImmediate(1)); \
299 } \
300 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
301 __ j(above_equal, ool->entry()); \
302 __ asm_instr(result, i.MemoryOperand(2)); \
303 __ bind(ool->exit()); \
304 } while (false)
305
306
307#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
308 do { \
309 auto offset = i.InputRegister(0); \
310 if (instr->InputAt(1)->IsRegister()) { \
311 __ cmp(offset, i.InputRegister(1)); \
312 } else { \
313 __ cmp(offset, i.InputImmediate(1)); \
314 } \
315 Label done; \
316 __ j(above_equal, &done, Label::kNear); \
317 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
318 __ bind(&done); \
319 } while (false)
320
321
322#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
323 do { \
324 auto offset = i.InputRegister(0); \
325 if (instr->InputAt(1)->IsRegister()) { \
326 __ cmp(offset, i.InputRegister(1)); \
327 } else { \
328 __ cmp(offset, i.InputImmediate(1)); \
329 } \
330 Label done; \
331 __ j(above_equal, &done, Label::kNear); \
332 if (instr->InputAt(2)->IsRegister()) { \
333 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
334 } else { \
335 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
336 } \
337 __ bind(&done); \
338 } while (false)
339
Ben Murdochda12d292016-06-02 14:46:10 +0100340#define ASSEMBLE_COMPARE(asm_instr) \
341 do { \
342 if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
343 size_t index = 0; \
344 Operand left = i.MemoryOperand(&index); \
345 if (HasImmediateInput(instr, index)) { \
346 __ asm_instr(left, i.InputImmediate(index)); \
347 } else { \
348 __ asm_instr(left, i.InputRegister(index)); \
349 } \
350 } else { \
351 if (HasImmediateInput(instr, 1)) { \
352 if (instr->InputAt(0)->IsRegister()) { \
353 __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
354 } else { \
355 __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
356 } \
357 } else { \
358 if (instr->InputAt(1)->IsRegister()) { \
359 __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
360 } else { \
361 __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
362 } \
363 } \
364 } \
365 } while (0)
366
Ben Murdoch61f157c2016-09-16 13:49:30 +0100367#define ASSEMBLE_IEEE754_BINOP(name) \
368 do { \
369 /* Pass two doubles as arguments on the stack. */ \
370 __ PrepareCallCFunction(4, eax); \
371 __ movsd(Operand(esp, 0 * kDoubleSize), i.InputDoubleRegister(0)); \
372 __ movsd(Operand(esp, 1 * kDoubleSize), i.InputDoubleRegister(1)); \
373 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
374 4); \
375 /* Return value is in st(0) on ia32. */ \
376 /* Store it into the result register. */ \
377 __ sub(esp, Immediate(kDoubleSize)); \
378 __ fstp_d(Operand(esp, 0)); \
379 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0)); \
380 __ add(esp, Immediate(kDoubleSize)); \
381 } while (false)
382
383#define ASSEMBLE_IEEE754_UNOP(name) \
384 do { \
385 /* Pass one double as argument on the stack. */ \
386 __ PrepareCallCFunction(2, eax); \
387 __ movsd(Operand(esp, 0 * kDoubleSize), i.InputDoubleRegister(0)); \
388 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
389 2); \
390 /* Return value is in st(0) on ia32. */ \
391 /* Store it into the result register. */ \
392 __ sub(esp, Immediate(kDoubleSize)); \
393 __ fstp_d(Operand(esp, 0)); \
394 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0)); \
395 __ add(esp, Immediate(kDoubleSize)); \
396 } while (false)
397
Ben Murdochda12d292016-06-02 14:46:10 +0100398void CodeGenerator::AssembleDeconstructFrame() {
399 __ mov(esp, ebp);
400 __ pop(ebp);
401}
402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
404 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
405 if (sp_slot_delta > 0) {
406 __ add(esp, Immediate(sp_slot_delta * kPointerSize));
407 }
408 frame_access_state()->SetFrameAccessToDefault();
409}
410
411
412void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
413 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
414 if (sp_slot_delta < 0) {
415 __ sub(esp, Immediate(-sp_slot_delta * kPointerSize));
416 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
417 }
Ben Murdochda12d292016-06-02 14:46:10 +0100418 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 __ mov(ebp, MemOperand(ebp, 0));
420 }
421 frame_access_state()->SetFrameAccessToSP();
422}
423
Ben Murdochda12d292016-06-02 14:46:10 +0100424void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
425 Register, Register,
426 Register) {
427 // There are not enough temp registers left on ia32 for a call instruction
428 // so we pick some scratch registers and save/restore them manually here.
429 int scratch_count = 3;
430 Register scratch1 = ebx;
431 Register scratch2 = ecx;
432 Register scratch3 = edx;
433 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
434 Label done;
435
436 // Check if current frame is an arguments adaptor frame.
437 __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset),
438 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
439 __ j(not_equal, &done, Label::kNear);
440
441 __ push(scratch1);
442 __ push(scratch2);
443 __ push(scratch3);
444
445 // Load arguments count from current arguments adaptor frame (note, it
446 // does not include receiver).
447 Register caller_args_count_reg = scratch1;
448 __ mov(caller_args_count_reg,
449 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
450 __ SmiUntag(caller_args_count_reg);
451
452 ParameterCount callee_args_count(args_reg);
453 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
454 scratch3, ReturnAddressState::kOnStack, scratch_count);
455 __ pop(scratch3);
456 __ pop(scratch2);
457 __ pop(scratch1);
458
459 __ bind(&done);
460}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462// Assembles an instruction after register allocation, producing machine code.
Ben Murdochc5610432016-08-08 18:44:38 +0100463CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
464 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 IA32OperandConverter i(this, instr);
Ben Murdochda12d292016-06-02 14:46:10 +0100466 InstructionCode opcode = instr->opcode();
467 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
468 switch (arch_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000469 case kArchCallCodeObject: {
470 EnsureSpaceForLazyDeopt();
471 if (HasImmediateInput(instr, 0)) {
472 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
473 __ call(code, RelocInfo::CODE_TARGET);
474 } else {
475 Register reg = i.InputRegister(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
477 __ call(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 RecordCallPosition(instr);
480 frame_access_state()->ClearSPDelta();
481 break;
482 }
Ben Murdochda12d292016-06-02 14:46:10 +0100483 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 case kArchTailCallCodeObject: {
485 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
486 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100487 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
488 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
489 no_reg, no_reg, no_reg);
490 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491 if (HasImmediateInput(instr, 0)) {
492 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
493 __ jmp(code, RelocInfo::CODE_TARGET);
494 } else {
495 Register reg = i.InputRegister(0);
496 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
497 __ jmp(reg);
498 }
499 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 break;
501 }
Ben Murdochc5610432016-08-08 18:44:38 +0100502 case kArchTailCallAddress: {
503 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
504 AssembleDeconstructActivationRecord(stack_param_delta);
505 CHECK(!HasImmediateInput(instr, 0));
506 Register reg = i.InputRegister(0);
507 __ jmp(reg);
508 frame_access_state()->ClearSPDelta();
509 break;
510 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 case kArchCallJSFunction: {
512 EnsureSpaceForLazyDeopt();
513 Register func = i.InputRegister(0);
514 if (FLAG_debug_code) {
515 // Check the function's context matches the context argument.
516 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
517 __ Assert(equal, kWrongFunctionContext);
518 }
519 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 RecordCallPosition(instr);
521 frame_access_state()->ClearSPDelta();
522 break;
523 }
Ben Murdochda12d292016-06-02 14:46:10 +0100524 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 case kArchTailCallJSFunction: {
526 Register func = i.InputRegister(0);
527 if (FLAG_debug_code) {
528 // Check the function's context matches the context argument.
529 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
530 __ Assert(equal, kWrongFunctionContext);
531 }
532 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
533 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100534 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
535 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
536 no_reg, no_reg, no_reg);
537 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
539 frame_access_state()->ClearSPDelta();
540 break;
541 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 case kArchPrepareCallCFunction: {
543 // Frame alignment requires using FP-relative frame addressing.
544 frame_access_state()->SetFrameAccessToFP();
545 int const num_parameters = MiscField::decode(instr->opcode());
546 __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
547 break;
548 }
549 case kArchPrepareTailCall:
550 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
551 break;
552 case kArchCallCFunction: {
553 int const num_parameters = MiscField::decode(instr->opcode());
554 if (HasImmediateInput(instr, 0)) {
555 ExternalReference ref = i.InputExternalReference(0);
556 __ CallCFunction(ref, num_parameters);
557 } else {
558 Register func = i.InputRegister(0);
559 __ CallCFunction(func, num_parameters);
560 }
561 frame_access_state()->SetFrameAccessToDefault();
562 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563 break;
564 }
565 case kArchJmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400566 AssembleArchJump(i.InputRpo(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568 case kArchLookupSwitch:
569 AssembleArchLookupSwitch(instr);
570 break;
571 case kArchTableSwitch:
572 AssembleArchTableSwitch(instr);
573 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100574 case kArchComment: {
575 Address comment_string = i.InputExternalReference(0).address();
576 __ RecordComment(reinterpret_cast<const char*>(comment_string));
577 break;
578 }
579 case kArchDebugBreak:
580 __ int3();
581 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583 case kArchThrowTerminator:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 // don't emit code for nops.
585 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000586 case kArchDeoptimize: {
587 int deopt_state_id =
588 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
589 Deoptimizer::BailoutType bailout_type =
590 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochc5610432016-08-08 18:44:38 +0100591 CodeGenResult result =
592 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
593 if (result != kSuccess) return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 break;
595 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 case kArchRet:
597 AssembleReturn();
598 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400599 case kArchStackPointer:
600 __ mov(i.OutputRegister(), esp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000602 case kArchFramePointer:
603 __ mov(i.OutputRegister(), ebp);
604 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100605 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100606 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100607 __ mov(i.OutputRegister(), Operand(ebp, 0));
608 } else {
609 __ mov(i.OutputRegister(), ebp);
610 }
611 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400612 case kArchTruncateDoubleToI: {
613 auto result = i.OutputRegister();
614 auto input = i.InputDoubleRegister(0);
615 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
616 __ cvttsd2si(result, Operand(input));
617 __ cmp(result, 1);
618 __ j(overflow, ool->entry());
619 __ bind(ool->exit());
620 break;
621 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 case kArchStoreWithWriteBarrier: {
623 RecordWriteMode mode =
624 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
625 Register object = i.InputRegister(0);
626 size_t index = 0;
627 Operand operand = i.MemoryOperand(&index);
628 Register value = i.InputRegister(index);
629 Register scratch0 = i.TempRegister(0);
630 Register scratch1 = i.TempRegister(1);
631 auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
632 scratch0, scratch1, mode);
633 __ mov(operand, value);
634 __ CheckPageFlag(object, scratch0,
635 MemoryChunk::kPointersFromHereAreInterestingMask,
636 not_zero, ool->entry());
637 __ bind(ool->exit());
638 break;
639 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100640 case kArchStackSlot: {
641 FrameOffset offset =
642 frame_access_state()->GetFrameOffset(i.InputInt32(0));
643 Register base;
644 if (offset.from_stack_pointer()) {
645 base = esp;
646 } else {
647 base = ebp;
648 }
649 __ lea(i.OutputRegister(), Operand(base, offset.offset()));
650 break;
651 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100652 case kIeee754Float64Atan:
653 ASSEMBLE_IEEE754_UNOP(atan);
654 break;
655 case kIeee754Float64Atan2:
656 ASSEMBLE_IEEE754_BINOP(atan2);
657 break;
658 case kIeee754Float64Cbrt:
659 ASSEMBLE_IEEE754_UNOP(cbrt);
660 break;
661 case kIeee754Float64Cos:
662 ASSEMBLE_IEEE754_UNOP(cos);
663 break;
664 case kIeee754Float64Expm1:
665 ASSEMBLE_IEEE754_UNOP(expm1);
666 break;
667 case kIeee754Float64Exp:
668 ASSEMBLE_IEEE754_UNOP(exp);
669 break;
670 case kIeee754Float64Atanh:
671 ASSEMBLE_IEEE754_UNOP(atanh);
672 break;
673 case kIeee754Float64Log:
674 ASSEMBLE_IEEE754_UNOP(log);
675 break;
676 case kIeee754Float64Log1p:
677 ASSEMBLE_IEEE754_UNOP(log1p);
678 break;
679 case kIeee754Float64Log2:
680 ASSEMBLE_IEEE754_UNOP(log2);
681 break;
682 case kIeee754Float64Log10:
683 ASSEMBLE_IEEE754_UNOP(log10);
684 break;
685 case kIeee754Float64Sin:
686 ASSEMBLE_IEEE754_UNOP(sin);
687 break;
688 case kIeee754Float64Tan:
689 ASSEMBLE_IEEE754_UNOP(tan);
690 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 case kIA32Add:
692 if (HasImmediateInput(instr, 1)) {
693 __ add(i.InputOperand(0), i.InputImmediate(1));
694 } else {
695 __ add(i.InputRegister(0), i.InputOperand(1));
696 }
697 break;
698 case kIA32And:
699 if (HasImmediateInput(instr, 1)) {
700 __ and_(i.InputOperand(0), i.InputImmediate(1));
701 } else {
702 __ and_(i.InputRegister(0), i.InputOperand(1));
703 }
704 break;
705 case kIA32Cmp:
Ben Murdochda12d292016-06-02 14:46:10 +0100706 ASSEMBLE_COMPARE(cmp);
707 break;
708 case kIA32Cmp16:
709 ASSEMBLE_COMPARE(cmpw);
710 break;
711 case kIA32Cmp8:
712 ASSEMBLE_COMPARE(cmpb);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 break;
714 case kIA32Test:
Ben Murdochda12d292016-06-02 14:46:10 +0100715 ASSEMBLE_COMPARE(test);
716 break;
717 case kIA32Test16:
718 ASSEMBLE_COMPARE(test_w);
719 break;
720 case kIA32Test8:
721 ASSEMBLE_COMPARE(test_b);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000722 break;
723 case kIA32Imul:
724 if (HasImmediateInput(instr, 1)) {
725 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
726 } else {
727 __ imul(i.OutputRegister(), i.InputOperand(1));
728 }
729 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400730 case kIA32ImulHigh:
731 __ imul(i.InputRegister(1));
732 break;
733 case kIA32UmulHigh:
734 __ mul(i.InputRegister(1));
735 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 case kIA32Idiv:
737 __ cdq();
738 __ idiv(i.InputOperand(1));
739 break;
740 case kIA32Udiv:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400741 __ Move(edx, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 __ div(i.InputOperand(1));
743 break;
744 case kIA32Not:
745 __ not_(i.OutputOperand());
746 break;
747 case kIA32Neg:
748 __ neg(i.OutputOperand());
749 break;
750 case kIA32Or:
751 if (HasImmediateInput(instr, 1)) {
752 __ or_(i.InputOperand(0), i.InputImmediate(1));
753 } else {
754 __ or_(i.InputRegister(0), i.InputOperand(1));
755 }
756 break;
757 case kIA32Xor:
758 if (HasImmediateInput(instr, 1)) {
759 __ xor_(i.InputOperand(0), i.InputImmediate(1));
760 } else {
761 __ xor_(i.InputRegister(0), i.InputOperand(1));
762 }
763 break;
764 case kIA32Sub:
765 if (HasImmediateInput(instr, 1)) {
766 __ sub(i.InputOperand(0), i.InputImmediate(1));
767 } else {
768 __ sub(i.InputRegister(0), i.InputOperand(1));
769 }
770 break;
771 case kIA32Shl:
772 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400773 __ shl(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400775 __ shl_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776 }
777 break;
778 case kIA32Shr:
779 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400780 __ shr(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 __ shr_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 }
784 break;
785 case kIA32Sar:
786 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400787 __ sar(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000788 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400789 __ sar_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790 }
791 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100792 case kIA32AddPair: {
793 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
794 // i.InputRegister(1) ... left high word.
795 // i.InputRegister(2) ... right low word.
796 // i.InputRegister(3) ... right high word.
797 bool use_temp = false;
798 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
799 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
800 // We cannot write to the output register directly, because it would
801 // overwrite an input for adc. We have to use the temp register.
802 use_temp = true;
803 __ Move(i.TempRegister(0), i.InputRegister(0));
804 __ add(i.TempRegister(0), i.InputRegister(2));
805 } else {
806 __ add(i.OutputRegister(0), i.InputRegister(2));
807 }
808 __ adc(i.InputRegister(1), Operand(i.InputRegister(3)));
809 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
810 __ Move(i.OutputRegister(1), i.InputRegister(1));
811 }
812 if (use_temp) {
813 __ Move(i.OutputRegister(0), i.TempRegister(0));
814 }
815 break;
816 }
817 case kIA32SubPair: {
818 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
819 // i.InputRegister(1) ... left high word.
820 // i.InputRegister(2) ... right low word.
821 // i.InputRegister(3) ... right high word.
822 bool use_temp = false;
823 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
824 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
825 // We cannot write to the output register directly, because it would
826 // overwrite an input for adc. We have to use the temp register.
827 use_temp = true;
828 __ Move(i.TempRegister(0), i.InputRegister(0));
829 __ sub(i.TempRegister(0), i.InputRegister(2));
830 } else {
831 __ sub(i.OutputRegister(0), i.InputRegister(2));
832 }
833 __ sbb(i.InputRegister(1), Operand(i.InputRegister(3)));
834 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
835 __ Move(i.OutputRegister(1), i.InputRegister(1));
836 }
837 if (use_temp) {
838 __ Move(i.OutputRegister(0), i.TempRegister(0));
839 }
840 break;
841 }
842 case kIA32MulPair: {
843 __ imul(i.OutputRegister(1), i.InputOperand(0));
844 __ mov(i.TempRegister(0), i.InputOperand(1));
845 __ imul(i.TempRegister(0), i.InputOperand(2));
846 __ add(i.OutputRegister(1), i.TempRegister(0));
847 __ mov(i.OutputRegister(0), i.InputOperand(0));
848 // Multiplies the low words and stores them in eax and edx.
849 __ mul(i.InputRegister(2));
850 __ add(i.OutputRegister(1), i.TempRegister(0));
851
852 break;
853 }
854 case kIA32ShlPair:
855 if (HasImmediateInput(instr, 2)) {
856 __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
857 } else {
858 // Shift has been loaded into CL by the register allocator.
859 __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0));
860 }
861 break;
862 case kIA32ShrPair:
863 if (HasImmediateInput(instr, 2)) {
864 __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
865 } else {
866 // Shift has been loaded into CL by the register allocator.
867 __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0));
868 }
869 break;
870 case kIA32SarPair:
871 if (HasImmediateInput(instr, 2)) {
872 __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
873 } else {
874 // Shift has been loaded into CL by the register allocator.
875 __ SarPair_cl(i.InputRegister(1), i.InputRegister(0));
876 }
877 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 case kIA32Ror:
879 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400880 __ ror(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000881 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400882 __ ror_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 }
884 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885 case kIA32Lzcnt:
886 __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
887 break;
888 case kIA32Tzcnt:
889 __ Tzcnt(i.OutputRegister(), i.InputOperand(0));
890 break;
891 case kIA32Popcnt:
892 __ Popcnt(i.OutputRegister(), i.InputOperand(0));
893 break;
894 case kSSEFloat32Cmp:
895 __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
896 break;
897 case kSSEFloat32Add:
898 __ addss(i.InputDoubleRegister(0), i.InputOperand(1));
899 break;
900 case kSSEFloat32Sub:
901 __ subss(i.InputDoubleRegister(0), i.InputOperand(1));
902 break;
903 case kSSEFloat32Mul:
904 __ mulss(i.InputDoubleRegister(0), i.InputOperand(1));
905 break;
906 case kSSEFloat32Div:
907 __ divss(i.InputDoubleRegister(0), i.InputOperand(1));
908 // Don't delete this mov. It may improve performance on some CPUs,
909 // when there is a (v)mulss depending on the result.
910 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
911 break;
912 case kSSEFloat32Max:
913 __ maxss(i.InputDoubleRegister(0), i.InputOperand(1));
914 break;
915 case kSSEFloat32Min:
916 __ minss(i.InputDoubleRegister(0), i.InputOperand(1));
917 break;
918 case kSSEFloat32Sqrt:
919 __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
920 break;
921 case kSSEFloat32Abs: {
922 // TODO(bmeurer): Use 128-bit constants.
923 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
924 __ psrlq(kScratchDoubleReg, 33);
925 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
926 break;
927 }
928 case kSSEFloat32Neg: {
929 // TODO(bmeurer): Use 128-bit constants.
930 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
931 __ psllq(kScratchDoubleReg, 31);
932 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
933 break;
934 }
935 case kSSEFloat32Round: {
936 CpuFeatureScope sse_scope(masm(), SSE4_1);
937 RoundingMode const mode =
938 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
939 __ roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
940 break;
941 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 case kSSEFloat64Cmp:
943 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
944 break;
945 case kSSEFloat64Add:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400946 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947 break;
948 case kSSEFloat64Sub:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400949 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000950 break;
951 case kSSEFloat64Mul:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400952 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 break;
954 case kSSEFloat64Div:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400955 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 // Don't delete this mov. It may improve performance on some CPUs,
957 // when there is a (v)mulsd depending on the result.
958 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
959 break;
960 case kSSEFloat64Max:
961 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
962 break;
963 case kSSEFloat64Min:
964 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000965 break;
966 case kSSEFloat64Mod: {
967 // TODO(dcarney): alignment is wrong.
968 __ sub(esp, Immediate(kDoubleSize));
969 // Move values to st(0) and st(1).
970 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
971 __ fld_d(Operand(esp, 0));
972 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
973 __ fld_d(Operand(esp, 0));
974 // Loop while fprem isn't done.
975 Label mod_loop;
976 __ bind(&mod_loop);
977 // This instructions traps on all kinds inputs, but we are assuming the
978 // floating point control word is set to ignore them all.
979 __ fprem();
980 // The following 2 instruction implicitly use eax.
981 __ fnstsw_ax();
982 __ sahf();
983 __ j(parity_even, &mod_loop);
984 // Move output to stack and clean up.
985 __ fstp(1);
986 __ fstp_d(Operand(esp, 0));
987 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
988 __ add(esp, Immediate(kDoubleSize));
989 break;
990 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000991 case kSSEFloat64Abs: {
992 // TODO(bmeurer): Use 128-bit constants.
993 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
994 __ psrlq(kScratchDoubleReg, 1);
995 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
996 break;
997 }
998 case kSSEFloat64Neg: {
999 // TODO(bmeurer): Use 128-bit constants.
1000 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1001 __ psllq(kScratchDoubleReg, 63);
1002 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
1003 break;
1004 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005 case kSSEFloat64Sqrt:
1006 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
1007 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 case kSSEFloat64Round: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001009 CpuFeatureScope sse_scope(masm(), SSE4_1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001010 RoundingMode const mode =
1011 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
1012 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001013 break;
1014 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015 case kSSEFloat32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001016 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
1017 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018 case kSSEFloat64ToFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001019 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
1020 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001021 case kSSEFloat32ToInt32:
1022 __ cvttss2si(i.OutputRegister(), i.InputOperand(0));
1023 break;
1024 case kSSEFloat32ToUint32: {
1025 Label success;
1026 __ cvttss2si(i.OutputRegister(), i.InputOperand(0));
1027 __ test(i.OutputRegister(), i.OutputRegister());
1028 __ j(positive, &success);
1029 __ Move(kScratchDoubleReg, static_cast<float>(INT32_MIN));
1030 __ addss(kScratchDoubleReg, i.InputOperand(0));
1031 __ cvttss2si(i.OutputRegister(), kScratchDoubleReg);
1032 __ or_(i.OutputRegister(), Immediate(0x80000000));
1033 __ bind(&success);
1034 break;
1035 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 case kSSEFloat64ToInt32:
1037 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
1038 break;
1039 case kSSEFloat64ToUint32: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001040 __ Move(kScratchDoubleReg, -2147483648.0);
1041 __ addsd(kScratchDoubleReg, i.InputOperand(0));
1042 __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043 __ add(i.OutputRegister(), Immediate(0x80000000));
1044 break;
1045 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001046 case kSSEInt32ToFloat32:
1047 __ cvtsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
1048 break;
1049 case kSSEUint32ToFloat32: {
1050 Register scratch0 = i.TempRegister(0);
1051 Register scratch1 = i.TempRegister(1);
1052 __ mov(scratch0, i.InputOperand(0));
1053 __ Cvtui2ss(i.OutputDoubleRegister(), scratch0, scratch1);
1054 break;
1055 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 case kSSEInt32ToFloat64:
1057 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
1058 break;
1059 case kSSEUint32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001060 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062 case kSSEFloat64ExtractLowWord32:
Ben Murdochc5610432016-08-08 18:44:38 +01001063 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001064 __ mov(i.OutputRegister(), i.InputOperand(0));
1065 } else {
1066 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
1067 }
1068 break;
1069 case kSSEFloat64ExtractHighWord32:
Ben Murdochc5610432016-08-08 18:44:38 +01001070 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
1072 } else {
1073 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
1074 }
1075 break;
1076 case kSSEFloat64InsertLowWord32:
1077 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
1078 break;
1079 case kSSEFloat64InsertHighWord32:
1080 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
1081 break;
1082 case kSSEFloat64LoadLowWord32:
1083 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
1084 break;
1085 case kAVXFloat32Add: {
1086 CpuFeatureScope avx_scope(masm(), AVX);
1087 __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1088 i.InputOperand(1));
1089 break;
1090 }
1091 case kAVXFloat32Sub: {
1092 CpuFeatureScope avx_scope(masm(), AVX);
1093 __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1094 i.InputOperand(1));
1095 break;
1096 }
1097 case kAVXFloat32Mul: {
1098 CpuFeatureScope avx_scope(masm(), AVX);
1099 __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1100 i.InputOperand(1));
1101 break;
1102 }
1103 case kAVXFloat32Div: {
1104 CpuFeatureScope avx_scope(masm(), AVX);
1105 __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1106 i.InputOperand(1));
1107 // Don't delete this mov. It may improve performance on some CPUs,
1108 // when there is a (v)mulss depending on the result.
1109 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1110 break;
1111 }
1112 case kAVXFloat32Max: {
1113 CpuFeatureScope avx_scope(masm(), AVX);
1114 __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1115 i.InputOperand(1));
1116 break;
1117 }
1118 case kAVXFloat32Min: {
1119 CpuFeatureScope avx_scope(masm(), AVX);
1120 __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1121 i.InputOperand(1));
1122 break;
1123 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001124 case kAVXFloat64Add: {
1125 CpuFeatureScope avx_scope(masm(), AVX);
1126 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1127 i.InputOperand(1));
1128 break;
1129 }
1130 case kAVXFloat64Sub: {
1131 CpuFeatureScope avx_scope(masm(), AVX);
1132 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1133 i.InputOperand(1));
1134 break;
1135 }
1136 case kAVXFloat64Mul: {
1137 CpuFeatureScope avx_scope(masm(), AVX);
1138 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1139 i.InputOperand(1));
1140 break;
1141 }
1142 case kAVXFloat64Div: {
1143 CpuFeatureScope avx_scope(masm(), AVX);
1144 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1145 i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 // Don't delete this mov. It may improve performance on some CPUs,
1147 // when there is a (v)mulsd depending on the result.
1148 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
1149 break;
1150 }
1151 case kAVXFloat64Max: {
1152 CpuFeatureScope avx_scope(masm(), AVX);
1153 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1154 i.InputOperand(1));
1155 break;
1156 }
1157 case kAVXFloat64Min: {
1158 CpuFeatureScope avx_scope(masm(), AVX);
1159 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1160 i.InputOperand(1));
1161 break;
1162 }
1163 case kAVXFloat32Abs: {
1164 // TODO(bmeurer): Use RIP relative 128-bit constants.
1165 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1166 __ psrlq(kScratchDoubleReg, 33);
1167 CpuFeatureScope avx_scope(masm(), AVX);
1168 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1169 break;
1170 }
1171 case kAVXFloat32Neg: {
1172 // TODO(bmeurer): Use RIP relative 128-bit constants.
1173 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1174 __ psllq(kScratchDoubleReg, 31);
1175 CpuFeatureScope avx_scope(masm(), AVX);
1176 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1177 break;
1178 }
1179 case kAVXFloat64Abs: {
1180 // TODO(bmeurer): Use RIP relative 128-bit constants.
1181 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1182 __ psrlq(kScratchDoubleReg, 1);
1183 CpuFeatureScope avx_scope(masm(), AVX);
1184 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
1185 break;
1186 }
1187 case kAVXFloat64Neg: {
1188 // TODO(bmeurer): Use RIP relative 128-bit constants.
1189 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
1190 __ psllq(kScratchDoubleReg, 63);
1191 CpuFeatureScope avx_scope(masm(), AVX);
1192 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001193 break;
1194 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001195 case kSSEFloat64SilenceNaN:
1196 __ xorpd(kScratchDoubleReg, kScratchDoubleReg);
1197 __ subsd(i.InputDoubleRegister(0), kScratchDoubleReg);
1198 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 case kIA32Movsxbl:
1200 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
1201 break;
1202 case kIA32Movzxbl:
1203 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
1204 break;
1205 case kIA32Movb: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001207 Operand operand = i.MemoryOperand(&index);
1208 if (HasImmediateInput(instr, index)) {
1209 __ mov_b(operand, i.InputInt8(index));
1210 } else {
1211 __ mov_b(operand, i.InputRegister(index));
1212 }
1213 break;
1214 }
1215 case kIA32Movsxwl:
1216 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
1217 break;
1218 case kIA32Movzxwl:
1219 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
1220 break;
1221 case kIA32Movw: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223 Operand operand = i.MemoryOperand(&index);
1224 if (HasImmediateInput(instr, index)) {
1225 __ mov_w(operand, i.InputInt16(index));
1226 } else {
1227 __ mov_w(operand, i.InputRegister(index));
1228 }
1229 break;
1230 }
1231 case kIA32Movl:
1232 if (instr->HasOutput()) {
1233 __ mov(i.OutputRegister(), i.MemoryOperand());
1234 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001235 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236 Operand operand = i.MemoryOperand(&index);
1237 if (HasImmediateInput(instr, index)) {
1238 __ mov(operand, i.InputImmediate(index));
1239 } else {
1240 __ mov(operand, i.InputRegister(index));
1241 }
1242 }
1243 break;
1244 case kIA32Movsd:
1245 if (instr->HasOutput()) {
1246 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
1247 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 Operand operand = i.MemoryOperand(&index);
1250 __ movsd(operand, i.InputDoubleRegister(index));
1251 }
1252 break;
1253 case kIA32Movss:
1254 if (instr->HasOutput()) {
1255 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258 Operand operand = i.MemoryOperand(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001259 __ movss(operand, i.InputDoubleRegister(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 }
1261 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001262 case kIA32BitcastFI:
Ben Murdochc5610432016-08-08 18:44:38 +01001263 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 __ mov(i.OutputRegister(), i.InputOperand(0));
1265 } else {
1266 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
1267 }
1268 break;
1269 case kIA32BitcastIF:
1270 if (instr->InputAt(0)->IsRegister()) {
1271 __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
1272 } else {
1273 __ movss(i.OutputDoubleRegister(), i.InputOperand(0));
1274 }
1275 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276 case kIA32Lea: {
1277 AddressingMode mode = AddressingModeField::decode(instr->opcode());
1278 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1279 // and addressing mode just happens to work out. The "addl"/"subl" forms
1280 // in these cases are faster based on measurements.
1281 if (mode == kMode_MI) {
1282 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
1283 } else if (i.InputRegister(0).is(i.OutputRegister())) {
1284 if (mode == kMode_MRI) {
1285 int32_t constant_summand = i.InputInt32(1);
1286 if (constant_summand > 0) {
1287 __ add(i.OutputRegister(), Immediate(constant_summand));
1288 } else if (constant_summand < 0) {
1289 __ sub(i.OutputRegister(), Immediate(-constant_summand));
1290 }
1291 } else if (mode == kMode_MR1) {
1292 if (i.InputRegister(1).is(i.OutputRegister())) {
1293 __ shl(i.OutputRegister(), 1);
1294 } else {
1295 __ lea(i.OutputRegister(), i.MemoryOperand());
1296 }
1297 } else if (mode == kMode_M2) {
1298 __ shl(i.OutputRegister(), 1);
1299 } else if (mode == kMode_M4) {
1300 __ shl(i.OutputRegister(), 2);
1301 } else if (mode == kMode_M8) {
1302 __ shl(i.OutputRegister(), 3);
1303 } else {
1304 __ lea(i.OutputRegister(), i.MemoryOperand());
1305 }
1306 } else {
1307 __ lea(i.OutputRegister(), i.MemoryOperand());
1308 }
1309 break;
1310 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001311 case kIA32PushFloat32:
Ben Murdochc5610432016-08-08 18:44:38 +01001312 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001313 __ sub(esp, Immediate(kFloatSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001314 __ movss(Operand(esp, 0), i.InputDoubleRegister(0));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001315 frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001316 } else if (HasImmediateInput(instr, 0)) {
1317 __ Move(kScratchDoubleReg, i.InputDouble(0));
1318 __ sub(esp, Immediate(kDoubleSize));
1319 __ movss(Operand(esp, 0), kScratchDoubleReg);
1320 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001321 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001322 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1323 __ sub(esp, Immediate(kDoubleSize));
1324 __ movss(Operand(esp, 0), kScratchDoubleReg);
1325 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001326 }
1327 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 case kIA32PushFloat64:
Ben Murdochc5610432016-08-08 18:44:38 +01001329 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001330 __ sub(esp, Immediate(kDoubleSize));
1331 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
1332 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1333 } else if (HasImmediateInput(instr, 0)) {
1334 __ Move(kScratchDoubleReg, i.InputDouble(0));
1335 __ sub(esp, Immediate(kDoubleSize));
1336 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1337 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1338 } else {
1339 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1340 __ sub(esp, Immediate(kDoubleSize));
1341 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1342 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1343 }
1344 break;
1345 case kIA32Push:
Ben Murdochc5610432016-08-08 18:44:38 +01001346 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001347 __ sub(esp, Immediate(kFloatSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001348 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001349 frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001350 } else if (HasImmediateInput(instr, 0)) {
1351 __ push(i.InputImmediate(0));
1352 frame_access_state()->IncreaseSPDelta(1);
1353 } else {
1354 __ push(i.InputOperand(0));
1355 frame_access_state()->IncreaseSPDelta(1);
1356 }
1357 break;
1358 case kIA32Poke: {
1359 int const slot = MiscField::decode(instr->opcode());
1360 if (HasImmediateInput(instr, 0)) {
1361 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
1362 } else {
1363 __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0));
1364 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365 break;
1366 }
Ben Murdochc5610432016-08-08 18:44:38 +01001367 case kIA32Xchgb: {
1368 size_t index = 0;
1369 Operand operand = i.MemoryOperand(&index);
1370 __ xchg_b(i.InputRegister(index), operand);
1371 break;
1372 }
1373 case kIA32Xchgw: {
1374 size_t index = 0;
1375 Operand operand = i.MemoryOperand(&index);
1376 __ xchg_w(i.InputRegister(index), operand);
1377 break;
1378 }
1379 case kIA32Xchgl: {
1380 size_t index = 0;
1381 Operand operand = i.MemoryOperand(&index);
1382 __ xchg(i.InputRegister(index), operand);
1383 break;
1384 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001385 case kCheckedLoadInt8:
1386 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
1387 break;
1388 case kCheckedLoadUint8:
1389 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
1390 break;
1391 case kCheckedLoadInt16:
1392 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
1393 break;
1394 case kCheckedLoadUint16:
1395 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
1396 break;
1397 case kCheckedLoadWord32:
1398 ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
1399 break;
1400 case kCheckedLoadFloat32:
1401 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
1402 break;
1403 case kCheckedLoadFloat64:
1404 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
1405 break;
1406 case kCheckedStoreWord8:
1407 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
1408 break;
1409 case kCheckedStoreWord16:
1410 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
1411 break;
1412 case kCheckedStoreWord32:
1413 ASSEMBLE_CHECKED_STORE_INTEGER(mov);
1414 break;
1415 case kCheckedStoreFloat32:
1416 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
1417 break;
1418 case kCheckedStoreFloat64:
1419 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
1420 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001421 case kIA32StackCheck: {
1422 ExternalReference const stack_limit =
1423 ExternalReference::address_of_stack_limit(isolate());
1424 __ cmp(esp, Operand::StaticVariable(stack_limit));
1425 break;
1426 }
1427 case kCheckedLoadWord64:
1428 case kCheckedStoreWord64:
1429 UNREACHABLE(); // currently unsupported checked int64 load/store.
1430 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001431 case kAtomicLoadInt8:
1432 case kAtomicLoadUint8:
1433 case kAtomicLoadInt16:
1434 case kAtomicLoadUint16:
1435 case kAtomicLoadWord32:
1436 case kAtomicStoreWord8:
1437 case kAtomicStoreWord16:
1438 case kAtomicStoreWord32:
1439 UNREACHABLE(); // Won't be generated by instruction selector.
1440 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441 }
Ben Murdochc5610432016-08-08 18:44:38 +01001442 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443} // NOLINT(readability/fn_size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001444
1445
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001446// Assembles a branch after an instruction.
1447void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448 IA32OperandConverter i(this, instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001449 Label::Distance flabel_distance =
1450 branch->fallthru ? Label::kNear : Label::kFar;
1451 Label* tlabel = branch->true_label;
1452 Label* flabel = branch->false_label;
1453 switch (branch->condition) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 case kUnorderedEqual:
1455 __ j(parity_even, flabel, flabel_distance);
1456 // Fall through.
1457 case kEqual:
1458 __ j(equal, tlabel);
1459 break;
1460 case kUnorderedNotEqual:
1461 __ j(parity_even, tlabel);
1462 // Fall through.
1463 case kNotEqual:
1464 __ j(not_equal, tlabel);
1465 break;
1466 case kSignedLessThan:
1467 __ j(less, tlabel);
1468 break;
1469 case kSignedGreaterThanOrEqual:
1470 __ j(greater_equal, tlabel);
1471 break;
1472 case kSignedLessThanOrEqual:
1473 __ j(less_equal, tlabel);
1474 break;
1475 case kSignedGreaterThan:
1476 __ j(greater, tlabel);
1477 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 case kUnsignedLessThan:
1479 __ j(below, tlabel);
1480 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481 case kUnsignedGreaterThanOrEqual:
1482 __ j(above_equal, tlabel);
1483 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 case kUnsignedLessThanOrEqual:
1485 __ j(below_equal, tlabel);
1486 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001487 case kUnsignedGreaterThan:
1488 __ j(above, tlabel);
1489 break;
1490 case kOverflow:
1491 __ j(overflow, tlabel);
1492 break;
1493 case kNotOverflow:
1494 __ j(no_overflow, tlabel);
1495 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001496 default:
1497 UNREACHABLE();
1498 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001500 // Add a jump if not falling through to the next block.
1501 if (!branch->fallthru) __ jmp(flabel);
1502}
1503
1504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001506 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507}
1508
1509
1510// Assembles boolean materializations after an instruction.
1511void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1512 FlagsCondition condition) {
1513 IA32OperandConverter i(this, instr);
1514 Label done;
1515
1516 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1517 // last output of the instruction.
1518 Label check;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 DCHECK_NE(0u, instr->OutputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001520 Register reg = i.OutputRegister(instr->OutputCount() - 1);
1521 Condition cc = no_condition;
1522 switch (condition) {
1523 case kUnorderedEqual:
1524 __ j(parity_odd, &check, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001525 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001526 __ jmp(&done, Label::kNear);
1527 // Fall through.
1528 case kEqual:
1529 cc = equal;
1530 break;
1531 case kUnorderedNotEqual:
1532 __ j(parity_odd, &check, Label::kNear);
1533 __ mov(reg, Immediate(1));
1534 __ jmp(&done, Label::kNear);
1535 // Fall through.
1536 case kNotEqual:
1537 cc = not_equal;
1538 break;
1539 case kSignedLessThan:
1540 cc = less;
1541 break;
1542 case kSignedGreaterThanOrEqual:
1543 cc = greater_equal;
1544 break;
1545 case kSignedLessThanOrEqual:
1546 cc = less_equal;
1547 break;
1548 case kSignedGreaterThan:
1549 cc = greater;
1550 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001551 case kUnsignedLessThan:
1552 cc = below;
1553 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001554 case kUnsignedGreaterThanOrEqual:
1555 cc = above_equal;
1556 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557 case kUnsignedLessThanOrEqual:
1558 cc = below_equal;
1559 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560 case kUnsignedGreaterThan:
1561 cc = above;
1562 break;
1563 case kOverflow:
1564 cc = overflow;
1565 break;
1566 case kNotOverflow:
1567 cc = no_overflow;
1568 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001569 default:
1570 UNREACHABLE();
1571 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 }
1573 __ bind(&check);
1574 if (reg.is_byte_register()) {
1575 // setcc for byte registers (al, bl, cl, dl).
1576 __ setcc(cc, reg);
1577 __ movzx_b(reg, reg);
1578 } else {
1579 // Emit a branch to set a register to either 1 or 0.
1580 Label set;
1581 __ j(cc, &set, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001582 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583 __ jmp(&done, Label::kNear);
1584 __ bind(&set);
1585 __ mov(reg, Immediate(1));
1586 }
1587 __ bind(&done);
1588}
1589
1590
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001591void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1592 IA32OperandConverter i(this, instr);
1593 Register input = i.InputRegister(0);
1594 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1595 __ cmp(input, Immediate(i.InputInt32(index + 0)));
1596 __ j(equal, GetLabel(i.InputRpo(index + 1)));
1597 }
1598 AssembleArchJump(i.InputRpo(1));
1599}
1600
1601
1602void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1603 IA32OperandConverter i(this, instr);
1604 Register input = i.InputRegister(0);
1605 size_t const case_count = instr->InputCount() - 2;
1606 Label** cases = zone()->NewArray<Label*>(case_count);
1607 for (size_t index = 0; index < case_count; ++index) {
1608 cases[index] = GetLabel(i.InputRpo(index + 2));
1609 }
1610 Label* const table = AddJumpTable(cases, case_count);
1611 __ cmp(input, Immediate(case_count));
1612 __ j(above_equal, GetLabel(i.InputRpo(1)));
1613 __ jmp(Operand::JumpTable(input, times_4, table));
1614}
1615
Ben Murdochc5610432016-08-08 18:44:38 +01001616CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001617 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001618 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001619 isolate(), deoptimization_id, bailout_type);
Ben Murdochc5610432016-08-08 18:44:38 +01001620 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001621 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochc5610432016-08-08 18:44:38 +01001622 return kSuccess;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001623}
1624
1625
1626// The calling convention for JSFunctions on IA32 passes arguments on the
1627// stack and the JSFunction and context in EDI and ESI, respectively, thus
1628// the steps of the call look as follows:
1629
1630// --{ before the call instruction }--------------------------------------------
1631// | caller frame |
1632// ^ esp ^ ebp
1633
1634// --{ push arguments and setup ESI, EDI }--------------------------------------
1635// | args + receiver | caller frame |
1636// ^ esp ^ ebp
1637// [edi = JSFunction, esi = context]
1638
1639// --{ call [edi + kCodeEntryOffset] }------------------------------------------
1640// | RET | args + receiver | caller frame |
1641// ^ esp ^ ebp
1642
1643// =={ prologue of called function }============================================
1644// --{ push ebp }---------------------------------------------------------------
1645// | FP | RET | args + receiver | caller frame |
1646// ^ esp ^ ebp
1647
1648// --{ mov ebp, esp }-----------------------------------------------------------
1649// | FP | RET | args + receiver | caller frame |
1650// ^ ebp,esp
1651
1652// --{ push esi }---------------------------------------------------------------
1653// | CTX | FP | RET | args + receiver | caller frame |
1654// ^esp ^ ebp
1655
1656// --{ push edi }---------------------------------------------------------------
1657// | FNC | CTX | FP | RET | args + receiver | caller frame |
1658// ^esp ^ ebp
1659
1660// --{ subi esp, #N }-----------------------------------------------------------
1661// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
1662// ^esp ^ ebp
1663
1664// =={ body of called function }================================================
1665
1666// =={ epilogue of called function }============================================
1667// --{ mov esp, ebp }-----------------------------------------------------------
1668// | FP | RET | args + receiver | caller frame |
1669// ^ esp,ebp
1670
1671// --{ pop ebp }-----------------------------------------------------------
1672// | | RET | args + receiver | caller frame |
1673// ^ esp ^ ebp
1674
1675// --{ ret #A+1 }-----------------------------------------------------------
1676// | | caller frame |
1677// ^ esp ^ ebp
1678
1679
1680// Runtime function calls are accomplished by doing a stub call to the
1681// CEntryStub (a real code object). On IA32 passes arguments on the
1682// stack, the number of arguments in EAX, the address of the runtime function
1683// in EBX, and the context in ESI.
1684
1685// --{ before the call instruction }--------------------------------------------
1686// | caller frame |
1687// ^ esp ^ ebp
1688
1689// --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
1690// | args + receiver | caller frame |
1691// ^ esp ^ ebp
1692// [eax = #args, ebx = runtime function, esi = context]
1693
1694// --{ call #CEntryStub }-------------------------------------------------------
1695// | RET | args + receiver | caller frame |
1696// ^ esp ^ ebp
1697
1698// =={ body of runtime function }===============================================
1699
1700// --{ runtime returns }--------------------------------------------------------
1701// | caller frame |
1702// ^ esp ^ ebp
1703
1704// Other custom linkages (e.g. for calling directly into and out of C++) may
1705// need to save callee-saved registers on the stack, which is done in the
1706// function prologue of generated code.
1707
1708// --{ before the call instruction }--------------------------------------------
1709// | caller frame |
1710// ^ esp ^ ebp
1711
1712// --{ set up arguments in registers on stack }---------------------------------
1713// | args | caller frame |
1714// ^ esp ^ ebp
1715// [r0 = arg0, r1 = arg1, ...]
1716
1717// --{ call code }--------------------------------------------------------------
1718// | RET | args | caller frame |
1719// ^ esp ^ ebp
1720
1721// =={ prologue of called function }============================================
1722// --{ push ebp }---------------------------------------------------------------
1723// | FP | RET | args | caller frame |
1724// ^ esp ^ ebp
1725
1726// --{ mov ebp, esp }-----------------------------------------------------------
1727// | FP | RET | args | caller frame |
1728// ^ ebp,esp
1729
1730// --{ save registers }---------------------------------------------------------
1731// | regs | FP | RET | args | caller frame |
1732// ^ esp ^ ebp
1733
1734// --{ subi esp, #N }-----------------------------------------------------------
1735// | callee frame | regs | FP | RET | args | caller frame |
1736// ^esp ^ ebp
1737
1738// =={ body of called function }================================================
1739
1740// =={ epilogue of called function }============================================
1741// --{ restore registers }------------------------------------------------------
1742// | regs | FP | RET | args | caller frame |
1743// ^ esp ^ ebp
1744
1745// --{ mov esp, ebp }-----------------------------------------------------------
1746// | FP | RET | args | caller frame |
1747// ^ esp,ebp
1748
1749// --{ pop ebp }----------------------------------------------------------------
1750// | RET | args | caller frame |
1751// ^ esp ^ ebp
1752
Ben Murdochc5610432016-08-08 18:44:38 +01001753void CodeGenerator::FinishFrame(Frame* frame) {
1754 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1755 const RegList saves = descriptor->CalleeSavedRegisters();
1756 if (saves != 0) { // Save callee-saved registers.
1757 DCHECK(!info()->is_osr());
1758 int pushed = 0;
1759 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1760 if (!((1 << i) & saves)) continue;
1761 ++pushed;
1762 }
1763 frame->AllocateSavedCalleeRegisterSlots(pushed);
1764 }
1765}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766
Ben Murdochc5610432016-08-08 18:44:38 +01001767void CodeGenerator::AssembleConstructFrame() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001768 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01001769 if (frame_access_state()->has_frame()) {
1770 if (descriptor->IsCFunctionCall()) {
1771 __ push(ebp);
1772 __ mov(ebp, esp);
1773 } else if (descriptor->IsJSFunctionCall()) {
1774 __ Prologue(this->info()->GeneratePreagedPrologue());
1775 } else {
1776 __ StubPrologue(info()->GetOutputStackFrameType());
1777 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 }
Ben Murdochc5610432016-08-08 18:44:38 +01001779
1780 int shrink_slots = frame()->GetSpillSlotCount();
1781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001782 if (info()->is_osr()) {
1783 // TurboFan OSR-compiled functions cannot be entered directly.
1784 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1785
1786 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1787 // frame is still on the stack. Optimized code uses OSR values directly from
1788 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1789 // remaining stack slots.
1790 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1791 osr_pc_offset_ = __ pc_offset();
Ben Murdochc5610432016-08-08 18:44:38 +01001792 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001793 }
1794
1795 const RegList saves = descriptor->CalleeSavedRegisters();
Ben Murdochc5610432016-08-08 18:44:38 +01001796 if (shrink_slots > 0) {
1797 __ sub(esp, Immediate(shrink_slots * kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001798 }
1799
1800 if (saves != 0) { // Save callee-saved registers.
1801 DCHECK(!info()->is_osr());
1802 int pushed = 0;
1803 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1804 if (!((1 << i) & saves)) continue;
1805 __ push(Register::from_code(i));
1806 ++pushed;
1807 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 }
1809}
1810
1811
1812void CodeGenerator::AssembleReturn() {
1813 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814
1815 const RegList saves = descriptor->CalleeSavedRegisters();
1816 // Restore registers.
1817 if (saves != 0) {
1818 for (int i = 0; i < Register::kNumRegisters; i++) {
1819 if (!((1 << i) & saves)) continue;
1820 __ pop(Register::from_code(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001821 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001822 }
1823
1824 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001825 AssembleDeconstructFrame();
1826 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001827 // Canonicalize JSFunction return sites for now.
1828 if (return_label_.is_bound()) {
1829 __ jmp(&return_label_);
1830 return;
1831 } else {
1832 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01001833 AssembleDeconstructFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001834 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001836 size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
1837 // Might need ecx for scratch if pop_size is too big.
1838 DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
1839 __ Ret(static_cast<int>(pop_size), ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840}
1841
1842
1843void CodeGenerator::AssembleMove(InstructionOperand* source,
1844 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001845 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001846 // Dispatch on the source and destination operand kinds. Not all
1847 // combinations are possible.
1848 if (source->IsRegister()) {
1849 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1850 Register src = g.ToRegister(source);
1851 Operand dst = g.ToOperand(destination);
1852 __ mov(dst, src);
1853 } else if (source->IsStackSlot()) {
1854 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1855 Operand src = g.ToOperand(source);
1856 if (destination->IsRegister()) {
1857 Register dst = g.ToRegister(destination);
1858 __ mov(dst, src);
1859 } else {
1860 Operand dst = g.ToOperand(destination);
1861 __ push(src);
1862 __ pop(dst);
1863 }
1864 } else if (source->IsConstant()) {
1865 Constant src_constant = g.ToConstant(source);
1866 if (src_constant.type() == Constant::kHeapObject) {
1867 Handle<HeapObject> src = src_constant.ToHeapObject();
Ben Murdochda12d292016-06-02 14:46:10 +01001868 int slot;
1869 if (IsMaterializableFromFrame(src, &slot)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001870 if (destination->IsRegister()) {
1871 Register dst = g.ToRegister(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01001872 __ mov(dst, g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001873 } else {
1874 DCHECK(destination->IsStackSlot());
1875 Operand dst = g.ToOperand(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01001876 __ push(g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001877 __ pop(dst);
1878 }
1879 } else if (destination->IsRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001880 Register dst = g.ToRegister(destination);
1881 __ LoadHeapObject(dst, src);
1882 } else {
1883 DCHECK(destination->IsStackSlot());
1884 Operand dst = g.ToOperand(destination);
1885 AllowDeferredHandleDereference embedding_raw_address;
1886 if (isolate()->heap()->InNewSpace(*src)) {
1887 __ PushHeapObject(src);
1888 __ pop(dst);
1889 } else {
1890 __ mov(dst, src);
1891 }
1892 }
1893 } else if (destination->IsRegister()) {
1894 Register dst = g.ToRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001895 __ Move(dst, g.ToImmediate(source));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001896 } else if (destination->IsStackSlot()) {
1897 Operand dst = g.ToOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001898 __ Move(dst, g.ToImmediate(source));
1899 } else if (src_constant.type() == Constant::kFloat32) {
1900 // TODO(turbofan): Can we do better here?
1901 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
Ben Murdochc5610432016-08-08 18:44:38 +01001902 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001903 XMMRegister dst = g.ToDoubleRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001904 __ Move(dst, src);
1905 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001906 DCHECK(destination->IsFPStackSlot());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001907 Operand dst = g.ToOperand(destination);
1908 __ Move(dst, Immediate(src));
1909 }
1910 } else {
1911 DCHECK_EQ(Constant::kFloat64, src_constant.type());
1912 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1913 uint32_t lower = static_cast<uint32_t>(src);
1914 uint32_t upper = static_cast<uint32_t>(src >> 32);
Ben Murdochc5610432016-08-08 18:44:38 +01001915 if (destination->IsFPRegister()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001916 XMMRegister dst = g.ToDoubleRegister(destination);
1917 __ Move(dst, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001919 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 Operand dst0 = g.ToOperand(destination);
1921 Operand dst1 = g.HighOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001922 __ Move(dst0, Immediate(lower));
1923 __ Move(dst1, Immediate(upper));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001924 }
1925 }
Ben Murdochc5610432016-08-08 18:44:38 +01001926 } else if (source->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001927 XMMRegister src = g.ToDoubleRegister(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001928 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 XMMRegister dst = g.ToDoubleRegister(destination);
1930 __ movaps(dst, src);
1931 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001932 DCHECK(destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 Operand dst = g.ToOperand(destination);
1934 __ movsd(dst, src);
1935 }
Ben Murdochc5610432016-08-08 18:44:38 +01001936 } else if (source->IsFPStackSlot()) {
1937 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001938 Operand src = g.ToOperand(source);
Ben Murdochc5610432016-08-08 18:44:38 +01001939 if (destination->IsFPRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001940 XMMRegister dst = g.ToDoubleRegister(destination);
1941 __ movsd(dst, src);
1942 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 Operand dst = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944 __ movsd(kScratchDoubleReg, src);
1945 __ movsd(dst, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001946 }
1947 } else {
1948 UNREACHABLE();
1949 }
1950}
1951
1952
1953void CodeGenerator::AssembleSwap(InstructionOperand* source,
1954 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001955 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001956 // Dispatch on the source and destination operand kinds. Not all
1957 // combinations are possible.
1958 if (source->IsRegister() && destination->IsRegister()) {
1959 // Register-register.
1960 Register src = g.ToRegister(source);
1961 Register dst = g.ToRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001962 __ push(src);
1963 __ mov(src, dst);
1964 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001965 } else if (source->IsRegister() && destination->IsStackSlot()) {
1966 // Register-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001967 Register src = g.ToRegister(source);
1968 __ push(src);
1969 frame_access_state()->IncreaseSPDelta(1);
1970 Operand dst = g.ToOperand(destination);
1971 __ mov(src, dst);
1972 frame_access_state()->IncreaseSPDelta(-1);
1973 dst = g.ToOperand(destination);
1974 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001975 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
1976 // Memory-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001977 Operand dst1 = g.ToOperand(destination);
1978 __ push(dst1);
1979 frame_access_state()->IncreaseSPDelta(1);
1980 Operand src1 = g.ToOperand(source);
1981 __ push(src1);
1982 Operand dst2 = g.ToOperand(destination);
1983 __ pop(dst2);
1984 frame_access_state()->IncreaseSPDelta(-1);
1985 Operand src2 = g.ToOperand(source);
1986 __ pop(src2);
Ben Murdochc5610432016-08-08 18:44:38 +01001987 } else if (source->IsFPRegister() && destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001988 // XMM register-register swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001989 XMMRegister src = g.ToDoubleRegister(source);
1990 XMMRegister dst = g.ToDoubleRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001991 __ movaps(kScratchDoubleReg, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001992 __ movaps(src, dst);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001993 __ movaps(dst, kScratchDoubleReg);
Ben Murdochc5610432016-08-08 18:44:38 +01001994 } else if (source->IsFPRegister() && destination->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 // XMM register-memory swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001996 XMMRegister reg = g.ToDoubleRegister(source);
1997 Operand other = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998 __ movsd(kScratchDoubleReg, other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001999 __ movsd(other, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002000 __ movaps(reg, kScratchDoubleReg);
Ben Murdochc5610432016-08-08 18:44:38 +01002001 } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002 // Double-width memory-to-memory.
2003 Operand src0 = g.ToOperand(source);
2004 Operand src1 = g.HighOperand(source);
2005 Operand dst0 = g.ToOperand(destination);
2006 Operand dst1 = g.HighOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002007 __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register.
2008 __ push(src0); // Then use stack to copy source to destination.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 __ pop(dst0);
2010 __ push(src1);
2011 __ pop(dst1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012 __ movsd(src0, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002013 } else {
2014 // No other combinations are possible.
2015 UNREACHABLE();
2016 }
2017}
2018
2019
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002020void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2021 for (size_t index = 0; index < target_count; ++index) {
2022 __ dd(targets[index]);
2023 }
2024}
2025
2026
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002028 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2029 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002030 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002031
2032 int space_needed = Deoptimizer::patch_size();
2033 // Ensure that we have enough space after the previous lazy-bailout
2034 // instruction for patching the code here.
2035 int current_pc = masm()->pc_offset();
2036 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2037 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2038 __ Nop(padding_size);
2039 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040}
2041
2042#undef __
2043
2044} // namespace compiler
2045} // namespace internal
2046} // namespace v8