blob: f63bc22e4344fe65a875ea3c7cc341a98caa362a [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 Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/ia32/assembler-ia32.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/ia32/frames-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014#include "src/ia32/macro-assembler-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20#define __ masm()->
21
22
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023#define kScratchDoubleReg xmm0
24
25
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026// Adds IA-32 specific methods for decoding operands.
27class IA32OperandConverter : public InstructionOperandConverter {
28 public:
29 IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
30 : InstructionOperandConverter(gen, instr) {}
31
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 Operand InputOperand(size_t index, int extra = 0) {
33 return ToOperand(instr_->InputAt(index), extra);
34 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 Immediate InputImmediate(size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037 return ToImmediate(instr_->InputAt(index));
38 }
39
40 Operand OutputOperand() { return ToOperand(instr_->Output()); }
41
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 Operand ToOperand(InstructionOperand* op, int extra = 0) {
43 if (op->IsRegister()) {
44 DCHECK(extra == 0);
45 return Operand(ToRegister(op));
46 } else if (op->IsDoubleRegister()) {
47 DCHECK(extra == 0);
48 return Operand(ToDoubleRegister(op));
49 }
50 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 FrameOffset offset = frame_access_state()->GetFrameOffset(
52 AllocatedOperand::cast(op)->index());
53 return Operand(offset.from_stack_pointer() ? esp : ebp,
54 offset.offset() + extra);
55 }
56
57 Operand ToMaterializableOperand(int materializable_offset) {
58 FrameOffset offset = frame_access_state()->GetFrameOffset(
59 Frame::FPOffsetToSlot(materializable_offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
61 }
62
63 Operand HighOperand(InstructionOperand* op) {
64 DCHECK(op->IsDoubleStackSlot());
65 return ToOperand(op, kPointerSize);
66 }
67
68 Immediate ToImmediate(InstructionOperand* operand) {
69 Constant constant = ToConstant(operand);
70 switch (constant.type()) {
71 case Constant::kInt32:
72 return Immediate(constant.ToInt32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040073 case Constant::kFloat32:
74 return Immediate(
75 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076 case Constant::kFloat64:
77 return Immediate(
78 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
79 case Constant::kExternalReference:
80 return Immediate(constant.ToExternalReference());
81 case Constant::kHeapObject:
82 return Immediate(constant.ToHeapObject());
83 case Constant::kInt64:
84 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 case Constant::kRpoNumber:
86 return Immediate::CodeRelativeOffset(ToLabel(operand));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 }
88 UNREACHABLE();
89 return Immediate(-1);
90 }
91
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 static size_t NextOffset(size_t* offset) {
93 size_t i = *offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040094 (*offset)++;
95 return i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096 }
97
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
99 STATIC_ASSERT(0 == static_cast<int>(times_1));
100 STATIC_ASSERT(1 == static_cast<int>(times_2));
101 STATIC_ASSERT(2 == static_cast<int>(times_4));
102 STATIC_ASSERT(3 == static_cast<int>(times_8));
103 int scale = static_cast<int>(mode - one);
104 DCHECK(scale >= 0 && scale < 4);
105 return static_cast<ScaleFactor>(scale);
106 }
107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 Operand MemoryOperand(size_t* offset) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
110 switch (mode) {
111 case kMode_MR: {
112 Register base = InputRegister(NextOffset(offset));
113 int32_t disp = 0;
114 return Operand(base, disp);
115 }
116 case kMode_MRI: {
117 Register base = InputRegister(NextOffset(offset));
118 int32_t disp = InputInt32(NextOffset(offset));
119 return Operand(base, disp);
120 }
121 case kMode_MR1:
122 case kMode_MR2:
123 case kMode_MR4:
124 case kMode_MR8: {
125 Register base = InputRegister(NextOffset(offset));
126 Register index = InputRegister(NextOffset(offset));
127 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
128 int32_t disp = 0;
129 return Operand(base, index, scale, disp);
130 }
131 case kMode_MR1I:
132 case kMode_MR2I:
133 case kMode_MR4I:
134 case kMode_MR8I: {
135 Register base = InputRegister(NextOffset(offset));
136 Register index = InputRegister(NextOffset(offset));
137 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
138 int32_t disp = InputInt32(NextOffset(offset));
139 return Operand(base, index, scale, disp);
140 }
141 case kMode_M1:
142 case kMode_M2:
143 case kMode_M4:
144 case kMode_M8: {
145 Register index = InputRegister(NextOffset(offset));
146 ScaleFactor scale = ScaleFor(kMode_M1, mode);
147 int32_t disp = 0;
148 return Operand(index, scale, disp);
149 }
150 case kMode_M1I:
151 case kMode_M2I:
152 case kMode_M4I:
153 case kMode_M8I: {
154 Register index = InputRegister(NextOffset(offset));
155 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
156 int32_t disp = InputInt32(NextOffset(offset));
157 return Operand(index, scale, disp);
158 }
159 case kMode_MI: {
160 int32_t disp = InputInt32(NextOffset(offset));
161 return Operand(Immediate(disp));
162 }
163 case kMode_None:
164 UNREACHABLE();
165 return Operand(no_reg, 0);
166 }
167 UNREACHABLE();
168 return Operand(no_reg, 0);
169 }
170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 Operand MemoryOperand(size_t first_input = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 return MemoryOperand(&first_input);
173 }
174};
175
176
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177namespace {
178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179bool HasImmediateInput(Instruction* instr, size_t index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 return instr->InputAt(index)->IsImmediate();
181}
182
183
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184class OutOfLineLoadInteger final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 public:
186 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
187 : OutOfLineCode(gen), result_(result) {}
188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189 void Generate() final { __ xor_(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190
191 private:
192 Register const result_;
193};
194
195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196class OutOfLineLoadFloat final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197 public:
198 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
199 : OutOfLineCode(gen), result_(result) {}
200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 void Generate() final { __ pcmpeqd(result_, result_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202
203 private:
204 XMMRegister const result_;
205};
206
207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400209 public:
210 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
211 XMMRegister input)
212 : OutOfLineCode(gen), result_(result), input_(input) {}
213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 void Generate() final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400215 __ sub(esp, Immediate(kDoubleSize));
216 __ movsd(MemOperand(esp, 0), input_);
217 __ SlowTruncateToI(result_, esp, 0);
218 __ add(esp, Immediate(kDoubleSize));
219 }
220
221 private:
222 Register const result_;
223 XMMRegister const input_;
224};
225
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226
227class OutOfLineRecordWrite final : public OutOfLineCode {
228 public:
229 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
230 Register value, Register scratch0, Register scratch1,
231 RecordWriteMode mode)
232 : OutOfLineCode(gen),
233 object_(object),
234 operand_(operand),
235 value_(value),
236 scratch0_(scratch0),
237 scratch1_(scratch1),
238 mode_(mode) {}
239
240 void Generate() final {
241 if (mode_ > RecordWriteMode::kValueIsPointer) {
242 __ JumpIfSmi(value_, exit());
243 }
244 if (mode_ > RecordWriteMode::kValueIsMap) {
245 __ CheckPageFlag(value_, scratch0_,
246 MemoryChunk::kPointersToHereAreInterestingMask, zero,
247 exit());
248 }
249 SaveFPRegsMode const save_fp_mode =
250 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
251 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
252 EMIT_REMEMBERED_SET, save_fp_mode);
253 __ lea(scratch1_, operand_);
254 __ CallStub(&stub);
255 }
256
257 private:
258 Register const object_;
259 Operand const operand_;
260 Register const value_;
261 Register const scratch0_;
262 Register const scratch1_;
263 RecordWriteMode const mode_;
264};
265
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400266} // namespace
267
268
269#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
270 do { \
271 auto result = i.OutputDoubleRegister(); \
272 auto offset = i.InputRegister(0); \
273 if (instr->InputAt(1)->IsRegister()) { \
274 __ cmp(offset, i.InputRegister(1)); \
275 } else { \
276 __ cmp(offset, i.InputImmediate(1)); \
277 } \
278 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
279 __ j(above_equal, ool->entry()); \
280 __ asm_instr(result, i.MemoryOperand(2)); \
281 __ bind(ool->exit()); \
282 } while (false)
283
284
285#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
286 do { \
287 auto result = i.OutputRegister(); \
288 auto offset = i.InputRegister(0); \
289 if (instr->InputAt(1)->IsRegister()) { \
290 __ cmp(offset, i.InputRegister(1)); \
291 } else { \
292 __ cmp(offset, i.InputImmediate(1)); \
293 } \
294 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
295 __ j(above_equal, ool->entry()); \
296 __ asm_instr(result, i.MemoryOperand(2)); \
297 __ bind(ool->exit()); \
298 } while (false)
299
300
301#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
302 do { \
303 auto offset = i.InputRegister(0); \
304 if (instr->InputAt(1)->IsRegister()) { \
305 __ cmp(offset, i.InputRegister(1)); \
306 } else { \
307 __ cmp(offset, i.InputImmediate(1)); \
308 } \
309 Label done; \
310 __ j(above_equal, &done, Label::kNear); \
311 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
312 __ bind(&done); \
313 } while (false)
314
315
316#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
317 do { \
318 auto offset = i.InputRegister(0); \
319 if (instr->InputAt(1)->IsRegister()) { \
320 __ cmp(offset, i.InputRegister(1)); \
321 } else { \
322 __ cmp(offset, i.InputImmediate(1)); \
323 } \
324 Label done; \
325 __ j(above_equal, &done, Label::kNear); \
326 if (instr->InputAt(2)->IsRegister()) { \
327 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
328 } else { \
329 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
330 } \
331 __ bind(&done); \
332 } while (false)
333
334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
336 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
337 if (sp_slot_delta > 0) {
338 __ add(esp, Immediate(sp_slot_delta * kPointerSize));
339 }
340 frame_access_state()->SetFrameAccessToDefault();
341}
342
343
344void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
345 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
346 if (sp_slot_delta < 0) {
347 __ sub(esp, Immediate(-sp_slot_delta * kPointerSize));
348 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
349 }
350 if (frame()->needs_frame()) {
351 __ mov(ebp, MemOperand(ebp, 0));
352 }
353 frame_access_state()->SetFrameAccessToSP();
354}
355
356
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357// Assembles an instruction after register allocation, producing machine code.
358void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
359 IA32OperandConverter i(this, instr);
360
361 switch (ArchOpcodeField::decode(instr->opcode())) {
362 case kArchCallCodeObject: {
363 EnsureSpaceForLazyDeopt();
364 if (HasImmediateInput(instr, 0)) {
365 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
366 __ call(code, RelocInfo::CODE_TARGET);
367 } else {
368 Register reg = i.InputRegister(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
370 __ call(reg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 RecordCallPosition(instr);
373 frame_access_state()->ClearSPDelta();
374 break;
375 }
376 case kArchTailCallCodeObject: {
377 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
378 AssembleDeconstructActivationRecord(stack_param_delta);
379 if (HasImmediateInput(instr, 0)) {
380 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
381 __ jmp(code, RelocInfo::CODE_TARGET);
382 } else {
383 Register reg = i.InputRegister(0);
384 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
385 __ jmp(reg);
386 }
387 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 break;
389 }
390 case kArchCallJSFunction: {
391 EnsureSpaceForLazyDeopt();
392 Register func = i.InputRegister(0);
393 if (FLAG_debug_code) {
394 // Check the function's context matches the context argument.
395 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
396 __ Assert(equal, kWrongFunctionContext);
397 }
398 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 RecordCallPosition(instr);
400 frame_access_state()->ClearSPDelta();
401 break;
402 }
403 case kArchTailCallJSFunction: {
404 Register func = i.InputRegister(0);
405 if (FLAG_debug_code) {
406 // Check the function's context matches the context argument.
407 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
408 __ Assert(equal, kWrongFunctionContext);
409 }
410 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
411 AssembleDeconstructActivationRecord(stack_param_delta);
412 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
413 frame_access_state()->ClearSPDelta();
414 break;
415 }
416 case kArchLazyBailout: {
417 EnsureSpaceForLazyDeopt();
418 RecordCallPosition(instr);
419 break;
420 }
421 case kArchPrepareCallCFunction: {
422 // Frame alignment requires using FP-relative frame addressing.
423 frame_access_state()->SetFrameAccessToFP();
424 int const num_parameters = MiscField::decode(instr->opcode());
425 __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
426 break;
427 }
428 case kArchPrepareTailCall:
429 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
430 break;
431 case kArchCallCFunction: {
432 int const num_parameters = MiscField::decode(instr->opcode());
433 if (HasImmediateInput(instr, 0)) {
434 ExternalReference ref = i.InputExternalReference(0);
435 __ CallCFunction(ref, num_parameters);
436 } else {
437 Register func = i.InputRegister(0);
438 __ CallCFunction(func, num_parameters);
439 }
440 frame_access_state()->SetFrameAccessToDefault();
441 frame_access_state()->ClearSPDelta();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 break;
443 }
444 case kArchJmp:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445 AssembleArchJump(i.InputRpo(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 case kArchLookupSwitch:
448 AssembleArchLookupSwitch(instr);
449 break;
450 case kArchTableSwitch:
451 AssembleArchTableSwitch(instr);
452 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 case kArchNop:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 case kArchThrowTerminator:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000455 // don't emit code for nops.
456 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 case kArchDeoptimize: {
458 int deopt_state_id =
459 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
460 Deoptimizer::BailoutType bailout_type =
461 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
462 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
463 break;
464 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 case kArchRet:
466 AssembleReturn();
467 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400468 case kArchStackPointer:
469 __ mov(i.OutputRegister(), esp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 case kArchFramePointer:
472 __ mov(i.OutputRegister(), ebp);
473 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400474 case kArchTruncateDoubleToI: {
475 auto result = i.OutputRegister();
476 auto input = i.InputDoubleRegister(0);
477 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
478 __ cvttsd2si(result, Operand(input));
479 __ cmp(result, 1);
480 __ j(overflow, ool->entry());
481 __ bind(ool->exit());
482 break;
483 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 case kArchStoreWithWriteBarrier: {
485 RecordWriteMode mode =
486 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
487 Register object = i.InputRegister(0);
488 size_t index = 0;
489 Operand operand = i.MemoryOperand(&index);
490 Register value = i.InputRegister(index);
491 Register scratch0 = i.TempRegister(0);
492 Register scratch1 = i.TempRegister(1);
493 auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
494 scratch0, scratch1, mode);
495 __ mov(operand, value);
496 __ CheckPageFlag(object, scratch0,
497 MemoryChunk::kPointersFromHereAreInterestingMask,
498 not_zero, ool->entry());
499 __ bind(ool->exit());
500 break;
501 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 case kIA32Add:
503 if (HasImmediateInput(instr, 1)) {
504 __ add(i.InputOperand(0), i.InputImmediate(1));
505 } else {
506 __ add(i.InputRegister(0), i.InputOperand(1));
507 }
508 break;
509 case kIA32And:
510 if (HasImmediateInput(instr, 1)) {
511 __ and_(i.InputOperand(0), i.InputImmediate(1));
512 } else {
513 __ and_(i.InputRegister(0), i.InputOperand(1));
514 }
515 break;
516 case kIA32Cmp:
517 if (HasImmediateInput(instr, 1)) {
518 __ cmp(i.InputOperand(0), i.InputImmediate(1));
519 } else {
520 __ cmp(i.InputRegister(0), i.InputOperand(1));
521 }
522 break;
523 case kIA32Test:
524 if (HasImmediateInput(instr, 1)) {
525 __ test(i.InputOperand(0), i.InputImmediate(1));
526 } else {
527 __ test(i.InputRegister(0), i.InputOperand(1));
528 }
529 break;
530 case kIA32Imul:
531 if (HasImmediateInput(instr, 1)) {
532 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
533 } else {
534 __ imul(i.OutputRegister(), i.InputOperand(1));
535 }
536 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400537 case kIA32ImulHigh:
538 __ imul(i.InputRegister(1));
539 break;
540 case kIA32UmulHigh:
541 __ mul(i.InputRegister(1));
542 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 case kIA32Idiv:
544 __ cdq();
545 __ idiv(i.InputOperand(1));
546 break;
547 case kIA32Udiv:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400548 __ Move(edx, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549 __ div(i.InputOperand(1));
550 break;
551 case kIA32Not:
552 __ not_(i.OutputOperand());
553 break;
554 case kIA32Neg:
555 __ neg(i.OutputOperand());
556 break;
557 case kIA32Or:
558 if (HasImmediateInput(instr, 1)) {
559 __ or_(i.InputOperand(0), i.InputImmediate(1));
560 } else {
561 __ or_(i.InputRegister(0), i.InputOperand(1));
562 }
563 break;
564 case kIA32Xor:
565 if (HasImmediateInput(instr, 1)) {
566 __ xor_(i.InputOperand(0), i.InputImmediate(1));
567 } else {
568 __ xor_(i.InputRegister(0), i.InputOperand(1));
569 }
570 break;
571 case kIA32Sub:
572 if (HasImmediateInput(instr, 1)) {
573 __ sub(i.InputOperand(0), i.InputImmediate(1));
574 } else {
575 __ sub(i.InputRegister(0), i.InputOperand(1));
576 }
577 break;
578 case kIA32Shl:
579 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400580 __ shl(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400582 __ shl_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 }
584 break;
585 case kIA32Shr:
586 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400587 __ shr(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400589 __ shr_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590 }
591 break;
592 case kIA32Sar:
593 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400594 __ sar(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400596 __ sar_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 }
598 break;
599 case kIA32Ror:
600 if (HasImmediateInput(instr, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400601 __ ror(i.OutputOperand(), i.InputInt5(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400603 __ ror_cl(i.OutputOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 }
605 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 case kIA32Lzcnt:
607 __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
608 break;
609 case kIA32Tzcnt:
610 __ Tzcnt(i.OutputRegister(), i.InputOperand(0));
611 break;
612 case kIA32Popcnt:
613 __ Popcnt(i.OutputRegister(), i.InputOperand(0));
614 break;
615 case kSSEFloat32Cmp:
616 __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
617 break;
618 case kSSEFloat32Add:
619 __ addss(i.InputDoubleRegister(0), i.InputOperand(1));
620 break;
621 case kSSEFloat32Sub:
622 __ subss(i.InputDoubleRegister(0), i.InputOperand(1));
623 break;
624 case kSSEFloat32Mul:
625 __ mulss(i.InputDoubleRegister(0), i.InputOperand(1));
626 break;
627 case kSSEFloat32Div:
628 __ divss(i.InputDoubleRegister(0), i.InputOperand(1));
629 // Don't delete this mov. It may improve performance on some CPUs,
630 // when there is a (v)mulss depending on the result.
631 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
632 break;
633 case kSSEFloat32Max:
634 __ maxss(i.InputDoubleRegister(0), i.InputOperand(1));
635 break;
636 case kSSEFloat32Min:
637 __ minss(i.InputDoubleRegister(0), i.InputOperand(1));
638 break;
639 case kSSEFloat32Sqrt:
640 __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
641 break;
642 case kSSEFloat32Abs: {
643 // TODO(bmeurer): Use 128-bit constants.
644 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
645 __ psrlq(kScratchDoubleReg, 33);
646 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg);
647 break;
648 }
649 case kSSEFloat32Neg: {
650 // TODO(bmeurer): Use 128-bit constants.
651 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
652 __ psllq(kScratchDoubleReg, 31);
653 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
654 break;
655 }
656 case kSSEFloat32Round: {
657 CpuFeatureScope sse_scope(masm(), SSE4_1);
658 RoundingMode const mode =
659 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
660 __ roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
661 break;
662 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663 case kSSEFloat64Cmp:
664 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
665 break;
666 case kSSEFloat64Add:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400667 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000668 break;
669 case kSSEFloat64Sub:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400670 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671 break;
672 case kSSEFloat64Mul:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400673 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 break;
675 case kSSEFloat64Div:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400676 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 // Don't delete this mov. It may improve performance on some CPUs,
678 // when there is a (v)mulsd depending on the result.
679 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
680 break;
681 case kSSEFloat64Max:
682 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
683 break;
684 case kSSEFloat64Min:
685 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000686 break;
687 case kSSEFloat64Mod: {
688 // TODO(dcarney): alignment is wrong.
689 __ sub(esp, Immediate(kDoubleSize));
690 // Move values to st(0) and st(1).
691 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
692 __ fld_d(Operand(esp, 0));
693 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
694 __ fld_d(Operand(esp, 0));
695 // Loop while fprem isn't done.
696 Label mod_loop;
697 __ bind(&mod_loop);
698 // This instructions traps on all kinds inputs, but we are assuming the
699 // floating point control word is set to ignore them all.
700 __ fprem();
701 // The following 2 instruction implicitly use eax.
702 __ fnstsw_ax();
703 __ sahf();
704 __ j(parity_even, &mod_loop);
705 // Move output to stack and clean up.
706 __ fstp(1);
707 __ fstp_d(Operand(esp, 0));
708 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
709 __ add(esp, Immediate(kDoubleSize));
710 break;
711 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 case kSSEFloat64Abs: {
713 // TODO(bmeurer): Use 128-bit constants.
714 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
715 __ psrlq(kScratchDoubleReg, 1);
716 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
717 break;
718 }
719 case kSSEFloat64Neg: {
720 // TODO(bmeurer): Use 128-bit constants.
721 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
722 __ psllq(kScratchDoubleReg, 63);
723 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
724 break;
725 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726 case kSSEFloat64Sqrt:
727 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
728 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729 case kSSEFloat64Round: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400730 CpuFeatureScope sse_scope(masm(), SSE4_1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 RoundingMode const mode =
732 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
733 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400734 break;
735 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 case kSSEFloat32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400737 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
738 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000739 case kSSEFloat64ToFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400740 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
741 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 case kSSEFloat64ToInt32:
743 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
744 break;
745 case kSSEFloat64ToUint32: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 __ Move(kScratchDoubleReg, -2147483648.0);
747 __ addsd(kScratchDoubleReg, i.InputOperand(0));
748 __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 __ add(i.OutputRegister(), Immediate(0x80000000));
750 break;
751 }
752 case kSSEInt32ToFloat64:
753 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
754 break;
755 case kSSEUint32ToFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400756 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000757 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758 case kSSEFloat64ExtractLowWord32:
759 if (instr->InputAt(0)->IsDoubleStackSlot()) {
760 __ mov(i.OutputRegister(), i.InputOperand(0));
761 } else {
762 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
763 }
764 break;
765 case kSSEFloat64ExtractHighWord32:
766 if (instr->InputAt(0)->IsDoubleStackSlot()) {
767 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
768 } else {
769 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
770 }
771 break;
772 case kSSEFloat64InsertLowWord32:
773 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
774 break;
775 case kSSEFloat64InsertHighWord32:
776 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
777 break;
778 case kSSEFloat64LoadLowWord32:
779 __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
780 break;
781 case kAVXFloat32Add: {
782 CpuFeatureScope avx_scope(masm(), AVX);
783 __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
784 i.InputOperand(1));
785 break;
786 }
787 case kAVXFloat32Sub: {
788 CpuFeatureScope avx_scope(masm(), AVX);
789 __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
790 i.InputOperand(1));
791 break;
792 }
793 case kAVXFloat32Mul: {
794 CpuFeatureScope avx_scope(masm(), AVX);
795 __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
796 i.InputOperand(1));
797 break;
798 }
799 case kAVXFloat32Div: {
800 CpuFeatureScope avx_scope(masm(), AVX);
801 __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
802 i.InputOperand(1));
803 // Don't delete this mov. It may improve performance on some CPUs,
804 // when there is a (v)mulss depending on the result.
805 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
806 break;
807 }
808 case kAVXFloat32Max: {
809 CpuFeatureScope avx_scope(masm(), AVX);
810 __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
811 i.InputOperand(1));
812 break;
813 }
814 case kAVXFloat32Min: {
815 CpuFeatureScope avx_scope(masm(), AVX);
816 __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
817 i.InputOperand(1));
818 break;
819 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400820 case kAVXFloat64Add: {
821 CpuFeatureScope avx_scope(masm(), AVX);
822 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
823 i.InputOperand(1));
824 break;
825 }
826 case kAVXFloat64Sub: {
827 CpuFeatureScope avx_scope(masm(), AVX);
828 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
829 i.InputOperand(1));
830 break;
831 }
832 case kAVXFloat64Mul: {
833 CpuFeatureScope avx_scope(masm(), AVX);
834 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
835 i.InputOperand(1));
836 break;
837 }
838 case kAVXFloat64Div: {
839 CpuFeatureScope avx_scope(masm(), AVX);
840 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
841 i.InputOperand(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842 // Don't delete this mov. It may improve performance on some CPUs,
843 // when there is a (v)mulsd depending on the result.
844 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister());
845 break;
846 }
847 case kAVXFloat64Max: {
848 CpuFeatureScope avx_scope(masm(), AVX);
849 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
850 i.InputOperand(1));
851 break;
852 }
853 case kAVXFloat64Min: {
854 CpuFeatureScope avx_scope(masm(), AVX);
855 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
856 i.InputOperand(1));
857 break;
858 }
859 case kAVXFloat32Abs: {
860 // TODO(bmeurer): Use RIP relative 128-bit constants.
861 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
862 __ psrlq(kScratchDoubleReg, 33);
863 CpuFeatureScope avx_scope(masm(), AVX);
864 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
865 break;
866 }
867 case kAVXFloat32Neg: {
868 // TODO(bmeurer): Use RIP relative 128-bit constants.
869 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
870 __ psllq(kScratchDoubleReg, 31);
871 CpuFeatureScope avx_scope(masm(), AVX);
872 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
873 break;
874 }
875 case kAVXFloat64Abs: {
876 // TODO(bmeurer): Use RIP relative 128-bit constants.
877 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
878 __ psrlq(kScratchDoubleReg, 1);
879 CpuFeatureScope avx_scope(masm(), AVX);
880 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
881 break;
882 }
883 case kAVXFloat64Neg: {
884 // TODO(bmeurer): Use RIP relative 128-bit constants.
885 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
886 __ psllq(kScratchDoubleReg, 63);
887 CpuFeatureScope avx_scope(masm(), AVX);
888 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400889 break;
890 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 case kIA32Movsxbl:
892 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
893 break;
894 case kIA32Movzxbl:
895 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
896 break;
897 case kIA32Movb: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000899 Operand operand = i.MemoryOperand(&index);
900 if (HasImmediateInput(instr, index)) {
901 __ mov_b(operand, i.InputInt8(index));
902 } else {
903 __ mov_b(operand, i.InputRegister(index));
904 }
905 break;
906 }
907 case kIA32Movsxwl:
908 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
909 break;
910 case kIA32Movzxwl:
911 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
912 break;
913 case kIA32Movw: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000915 Operand operand = i.MemoryOperand(&index);
916 if (HasImmediateInput(instr, index)) {
917 __ mov_w(operand, i.InputInt16(index));
918 } else {
919 __ mov_w(operand, i.InputRegister(index));
920 }
921 break;
922 }
923 case kIA32Movl:
924 if (instr->HasOutput()) {
925 __ mov(i.OutputRegister(), i.MemoryOperand());
926 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928 Operand operand = i.MemoryOperand(&index);
929 if (HasImmediateInput(instr, index)) {
930 __ mov(operand, i.InputImmediate(index));
931 } else {
932 __ mov(operand, i.InputRegister(index));
933 }
934 }
935 break;
936 case kIA32Movsd:
937 if (instr->HasOutput()) {
938 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
939 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000940 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941 Operand operand = i.MemoryOperand(&index);
942 __ movsd(operand, i.InputDoubleRegister(index));
943 }
944 break;
945 case kIA32Movss:
946 if (instr->HasOutput()) {
947 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000948 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 size_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000950 Operand operand = i.MemoryOperand(&index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400951 __ movss(operand, i.InputDoubleRegister(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952 }
953 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 case kIA32BitcastFI:
955 if (instr->InputAt(0)->IsDoubleStackSlot()) {
956 __ mov(i.OutputRegister(), i.InputOperand(0));
957 } else {
958 __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
959 }
960 break;
961 case kIA32BitcastIF:
962 if (instr->InputAt(0)->IsRegister()) {
963 __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
964 } else {
965 __ movss(i.OutputDoubleRegister(), i.InputOperand(0));
966 }
967 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400968 case kIA32Lea: {
969 AddressingMode mode = AddressingModeField::decode(instr->opcode());
970 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
971 // and addressing mode just happens to work out. The "addl"/"subl" forms
972 // in these cases are faster based on measurements.
973 if (mode == kMode_MI) {
974 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
975 } else if (i.InputRegister(0).is(i.OutputRegister())) {
976 if (mode == kMode_MRI) {
977 int32_t constant_summand = i.InputInt32(1);
978 if (constant_summand > 0) {
979 __ add(i.OutputRegister(), Immediate(constant_summand));
980 } else if (constant_summand < 0) {
981 __ sub(i.OutputRegister(), Immediate(-constant_summand));
982 }
983 } else if (mode == kMode_MR1) {
984 if (i.InputRegister(1).is(i.OutputRegister())) {
985 __ shl(i.OutputRegister(), 1);
986 } else {
987 __ lea(i.OutputRegister(), i.MemoryOperand());
988 }
989 } else if (mode == kMode_M2) {
990 __ shl(i.OutputRegister(), 1);
991 } else if (mode == kMode_M4) {
992 __ shl(i.OutputRegister(), 2);
993 } else if (mode == kMode_M8) {
994 __ shl(i.OutputRegister(), 3);
995 } else {
996 __ lea(i.OutputRegister(), i.MemoryOperand());
997 }
998 } else {
999 __ lea(i.OutputRegister(), i.MemoryOperand());
1000 }
1001 break;
1002 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003 case kIA32PushFloat32:
1004 if (instr->InputAt(0)->IsDoubleRegister()) {
1005 __ sub(esp, Immediate(kDoubleSize));
1006 __ movss(Operand(esp, 0), i.InputDoubleRegister(0));
1007 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1008 } else if (HasImmediateInput(instr, 0)) {
1009 __ Move(kScratchDoubleReg, i.InputDouble(0));
1010 __ sub(esp, Immediate(kDoubleSize));
1011 __ movss(Operand(esp, 0), kScratchDoubleReg);
1012 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001014 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1015 __ sub(esp, Immediate(kDoubleSize));
1016 __ movss(Operand(esp, 0), kScratchDoubleReg);
1017 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001018 }
1019 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001020 case kIA32PushFloat64:
1021 if (instr->InputAt(0)->IsDoubleRegister()) {
1022 __ sub(esp, Immediate(kDoubleSize));
1023 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
1024 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1025 } else if (HasImmediateInput(instr, 0)) {
1026 __ Move(kScratchDoubleReg, i.InputDouble(0));
1027 __ sub(esp, Immediate(kDoubleSize));
1028 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1029 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1030 } else {
1031 __ movsd(kScratchDoubleReg, i.InputOperand(0));
1032 __ sub(esp, Immediate(kDoubleSize));
1033 __ movsd(Operand(esp, 0), kScratchDoubleReg);
1034 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1035 }
1036 break;
1037 case kIA32Push:
1038 if (instr->InputAt(0)->IsDoubleRegister()) {
1039 __ sub(esp, Immediate(kDoubleSize));
1040 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
1041 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1042 } else if (HasImmediateInput(instr, 0)) {
1043 __ push(i.InputImmediate(0));
1044 frame_access_state()->IncreaseSPDelta(1);
1045 } else {
1046 __ push(i.InputOperand(0));
1047 frame_access_state()->IncreaseSPDelta(1);
1048 }
1049 break;
1050 case kIA32Poke: {
1051 int const slot = MiscField::decode(instr->opcode());
1052 if (HasImmediateInput(instr, 0)) {
1053 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
1054 } else {
1055 __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0));
1056 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057 break;
1058 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001059 case kCheckedLoadInt8:
1060 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
1061 break;
1062 case kCheckedLoadUint8:
1063 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
1064 break;
1065 case kCheckedLoadInt16:
1066 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
1067 break;
1068 case kCheckedLoadUint16:
1069 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
1070 break;
1071 case kCheckedLoadWord32:
1072 ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
1073 break;
1074 case kCheckedLoadFloat32:
1075 ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
1076 break;
1077 case kCheckedLoadFloat64:
1078 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
1079 break;
1080 case kCheckedStoreWord8:
1081 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
1082 break;
1083 case kCheckedStoreWord16:
1084 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
1085 break;
1086 case kCheckedStoreWord32:
1087 ASSEMBLE_CHECKED_STORE_INTEGER(mov);
1088 break;
1089 case kCheckedStoreFloat32:
1090 ASSEMBLE_CHECKED_STORE_FLOAT(movss);
1091 break;
1092 case kCheckedStoreFloat64:
1093 ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
1094 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 case kIA32StackCheck: {
1096 ExternalReference const stack_limit =
1097 ExternalReference::address_of_stack_limit(isolate());
1098 __ cmp(esp, Operand::StaticVariable(stack_limit));
1099 break;
1100 }
1101 case kCheckedLoadWord64:
1102 case kCheckedStoreWord64:
1103 UNREACHABLE(); // currently unsupported checked int64 load/store.
1104 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001106} // NOLINT(readability/fn_size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107
1108
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001109// Assembles a branch after an instruction.
1110void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001111 IA32OperandConverter i(this, instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001112 Label::Distance flabel_distance =
1113 branch->fallthru ? Label::kNear : Label::kFar;
1114 Label* tlabel = branch->true_label;
1115 Label* flabel = branch->false_label;
1116 switch (branch->condition) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001117 case kUnorderedEqual:
1118 __ j(parity_even, flabel, flabel_distance);
1119 // Fall through.
1120 case kEqual:
1121 __ j(equal, tlabel);
1122 break;
1123 case kUnorderedNotEqual:
1124 __ j(parity_even, tlabel);
1125 // Fall through.
1126 case kNotEqual:
1127 __ j(not_equal, tlabel);
1128 break;
1129 case kSignedLessThan:
1130 __ j(less, tlabel);
1131 break;
1132 case kSignedGreaterThanOrEqual:
1133 __ j(greater_equal, tlabel);
1134 break;
1135 case kSignedLessThanOrEqual:
1136 __ j(less_equal, tlabel);
1137 break;
1138 case kSignedGreaterThan:
1139 __ j(greater, tlabel);
1140 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141 case kUnsignedLessThan:
1142 __ j(below, tlabel);
1143 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001144 case kUnsignedGreaterThanOrEqual:
1145 __ j(above_equal, tlabel);
1146 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 case kUnsignedLessThanOrEqual:
1148 __ j(below_equal, tlabel);
1149 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001150 case kUnsignedGreaterThan:
1151 __ j(above, tlabel);
1152 break;
1153 case kOverflow:
1154 __ j(overflow, tlabel);
1155 break;
1156 case kNotOverflow:
1157 __ j(no_overflow, tlabel);
1158 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 default:
1160 UNREACHABLE();
1161 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001163 // Add a jump if not falling through to the next block.
1164 if (!branch->fallthru) __ jmp(flabel);
1165}
1166
1167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001168void CodeGenerator::AssembleArchJump(RpoNumber target) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001169 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170}
1171
1172
1173// Assembles boolean materializations after an instruction.
1174void CodeGenerator::AssembleArchBoolean(Instruction* instr,
1175 FlagsCondition condition) {
1176 IA32OperandConverter i(this, instr);
1177 Label done;
1178
1179 // Materialize a full 32-bit 1 or 0 value. The result register is always the
1180 // last output of the instruction.
1181 Label check;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182 DCHECK_NE(0u, instr->OutputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183 Register reg = i.OutputRegister(instr->OutputCount() - 1);
1184 Condition cc = no_condition;
1185 switch (condition) {
1186 case kUnorderedEqual:
1187 __ j(parity_odd, &check, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001188 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001189 __ jmp(&done, Label::kNear);
1190 // Fall through.
1191 case kEqual:
1192 cc = equal;
1193 break;
1194 case kUnorderedNotEqual:
1195 __ j(parity_odd, &check, Label::kNear);
1196 __ mov(reg, Immediate(1));
1197 __ jmp(&done, Label::kNear);
1198 // Fall through.
1199 case kNotEqual:
1200 cc = not_equal;
1201 break;
1202 case kSignedLessThan:
1203 cc = less;
1204 break;
1205 case kSignedGreaterThanOrEqual:
1206 cc = greater_equal;
1207 break;
1208 case kSignedLessThanOrEqual:
1209 cc = less_equal;
1210 break;
1211 case kSignedGreaterThan:
1212 cc = greater;
1213 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 case kUnsignedLessThan:
1215 cc = below;
1216 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 case kUnsignedGreaterThanOrEqual:
1218 cc = above_equal;
1219 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001220 case kUnsignedLessThanOrEqual:
1221 cc = below_equal;
1222 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223 case kUnsignedGreaterThan:
1224 cc = above;
1225 break;
1226 case kOverflow:
1227 cc = overflow;
1228 break;
1229 case kNotOverflow:
1230 cc = no_overflow;
1231 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 default:
1233 UNREACHABLE();
1234 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 }
1236 __ bind(&check);
1237 if (reg.is_byte_register()) {
1238 // setcc for byte registers (al, bl, cl, dl).
1239 __ setcc(cc, reg);
1240 __ movzx_b(reg, reg);
1241 } else {
1242 // Emit a branch to set a register to either 1 or 0.
1243 Label set;
1244 __ j(cc, &set, Label::kNear);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001245 __ Move(reg, Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246 __ jmp(&done, Label::kNear);
1247 __ bind(&set);
1248 __ mov(reg, Immediate(1));
1249 }
1250 __ bind(&done);
1251}
1252
1253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
1255 IA32OperandConverter i(this, instr);
1256 Register input = i.InputRegister(0);
1257 for (size_t index = 2; index < instr->InputCount(); index += 2) {
1258 __ cmp(input, Immediate(i.InputInt32(index + 0)));
1259 __ j(equal, GetLabel(i.InputRpo(index + 1)));
1260 }
1261 AssembleArchJump(i.InputRpo(1));
1262}
1263
1264
1265void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
1266 IA32OperandConverter i(this, instr);
1267 Register input = i.InputRegister(0);
1268 size_t const case_count = instr->InputCount() - 2;
1269 Label** cases = zone()->NewArray<Label*>(case_count);
1270 for (size_t index = 0; index < case_count; ++index) {
1271 cases[index] = GetLabel(i.InputRpo(index + 2));
1272 }
1273 Label* const table = AddJumpTable(cases, case_count);
1274 __ cmp(input, Immediate(case_count));
1275 __ j(above_equal, GetLabel(i.InputRpo(1)));
1276 __ jmp(Operand::JumpTable(input, times_4, table));
1277}
1278
1279
1280void CodeGenerator::AssembleDeoptimizerCall(
1281 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001283 isolate(), deoptimization_id, bailout_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
1285}
1286
1287
1288// The calling convention for JSFunctions on IA32 passes arguments on the
1289// stack and the JSFunction and context in EDI and ESI, respectively, thus
1290// the steps of the call look as follows:
1291
1292// --{ before the call instruction }--------------------------------------------
1293// | caller frame |
1294// ^ esp ^ ebp
1295
1296// --{ push arguments and setup ESI, EDI }--------------------------------------
1297// | args + receiver | caller frame |
1298// ^ esp ^ ebp
1299// [edi = JSFunction, esi = context]
1300
1301// --{ call [edi + kCodeEntryOffset] }------------------------------------------
1302// | RET | args + receiver | caller frame |
1303// ^ esp ^ ebp
1304
1305// =={ prologue of called function }============================================
1306// --{ push ebp }---------------------------------------------------------------
1307// | FP | RET | args + receiver | caller frame |
1308// ^ esp ^ ebp
1309
1310// --{ mov ebp, esp }-----------------------------------------------------------
1311// | FP | RET | args + receiver | caller frame |
1312// ^ ebp,esp
1313
1314// --{ push esi }---------------------------------------------------------------
1315// | CTX | FP | RET | args + receiver | caller frame |
1316// ^esp ^ ebp
1317
1318// --{ push edi }---------------------------------------------------------------
1319// | FNC | CTX | FP | RET | args + receiver | caller frame |
1320// ^esp ^ ebp
1321
1322// --{ subi esp, #N }-----------------------------------------------------------
1323// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
1324// ^esp ^ ebp
1325
1326// =={ body of called function }================================================
1327
1328// =={ epilogue of called function }============================================
1329// --{ mov esp, ebp }-----------------------------------------------------------
1330// | FP | RET | args + receiver | caller frame |
1331// ^ esp,ebp
1332
1333// --{ pop ebp }-----------------------------------------------------------
1334// | | RET | args + receiver | caller frame |
1335// ^ esp ^ ebp
1336
1337// --{ ret #A+1 }-----------------------------------------------------------
1338// | | caller frame |
1339// ^ esp ^ ebp
1340
1341
1342// Runtime function calls are accomplished by doing a stub call to the
1343// CEntryStub (a real code object). On IA32 passes arguments on the
1344// stack, the number of arguments in EAX, the address of the runtime function
1345// in EBX, and the context in ESI.
1346
1347// --{ before the call instruction }--------------------------------------------
1348// | caller frame |
1349// ^ esp ^ ebp
1350
1351// --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
1352// | args + receiver | caller frame |
1353// ^ esp ^ ebp
1354// [eax = #args, ebx = runtime function, esi = context]
1355
1356// --{ call #CEntryStub }-------------------------------------------------------
1357// | RET | args + receiver | caller frame |
1358// ^ esp ^ ebp
1359
1360// =={ body of runtime function }===============================================
1361
1362// --{ runtime returns }--------------------------------------------------------
1363// | caller frame |
1364// ^ esp ^ ebp
1365
1366// Other custom linkages (e.g. for calling directly into and out of C++) may
1367// need to save callee-saved registers on the stack, which is done in the
1368// function prologue of generated code.
1369
1370// --{ before the call instruction }--------------------------------------------
1371// | caller frame |
1372// ^ esp ^ ebp
1373
1374// --{ set up arguments in registers on stack }---------------------------------
1375// | args | caller frame |
1376// ^ esp ^ ebp
1377// [r0 = arg0, r1 = arg1, ...]
1378
1379// --{ call code }--------------------------------------------------------------
1380// | RET | args | caller frame |
1381// ^ esp ^ ebp
1382
1383// =={ prologue of called function }============================================
1384// --{ push ebp }---------------------------------------------------------------
1385// | FP | RET | args | caller frame |
1386// ^ esp ^ ebp
1387
1388// --{ mov ebp, esp }-----------------------------------------------------------
1389// | FP | RET | args | caller frame |
1390// ^ ebp,esp
1391
1392// --{ save registers }---------------------------------------------------------
1393// | regs | FP | RET | args | caller frame |
1394// ^ esp ^ ebp
1395
1396// --{ subi esp, #N }-----------------------------------------------------------
1397// | callee frame | regs | FP | RET | args | caller frame |
1398// ^esp ^ ebp
1399
1400// =={ body of called function }================================================
1401
1402// =={ epilogue of called function }============================================
1403// --{ restore registers }------------------------------------------------------
1404// | regs | FP | RET | args | caller frame |
1405// ^ esp ^ ebp
1406
1407// --{ mov esp, ebp }-----------------------------------------------------------
1408// | FP | RET | args | caller frame |
1409// ^ esp,ebp
1410
1411// --{ pop ebp }----------------------------------------------------------------
1412// | RET | args | caller frame |
1413// ^ esp ^ ebp
1414
1415
1416void CodeGenerator::AssemblePrologue() {
1417 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001418 if (descriptor->IsCFunctionCall()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 // Assemble a prologue similar the to cdecl calling convention.
1420 __ push(ebp);
1421 __ mov(ebp, esp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 } else if (descriptor->IsJSFunctionCall()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 // TODO(turbofan): this prologue is redundant with OSR, but still needed for
1424 // code aging.
1425 __ Prologue(this->info()->GeneratePreagedPrologue());
1426 } else if (frame()->needs_frame()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 __ StubPrologue();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 } else {
1429 frame()->SetElidedFrameSizeInSlots(kPCOnStackSize / kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001431 frame_access_state()->SetFrameAccessToDefault();
1432
1433 int stack_shrink_slots = frame()->GetSpillSlotCount();
1434 if (info()->is_osr()) {
1435 // TurboFan OSR-compiled functions cannot be entered directly.
1436 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1437
1438 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1439 // frame is still on the stack. Optimized code uses OSR values directly from
1440 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1441 // remaining stack slots.
1442 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1443 osr_pc_offset_ = __ pc_offset();
1444 // TODO(titzer): cannot address target function == local #-1
1445 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1446 stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
1447 }
1448
1449 const RegList saves = descriptor->CalleeSavedRegisters();
1450 if (stack_shrink_slots > 0) {
1451 __ sub(esp, Immediate(stack_shrink_slots * kPointerSize));
1452 }
1453
1454 if (saves != 0) { // Save callee-saved registers.
1455 DCHECK(!info()->is_osr());
1456 int pushed = 0;
1457 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1458 if (!((1 << i) & saves)) continue;
1459 __ push(Register::from_code(i));
1460 ++pushed;
1461 }
1462 frame()->AllocateSavedCalleeRegisterSlots(pushed);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 }
1464}
1465
1466
1467void CodeGenerator::AssembleReturn() {
1468 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001469
1470 const RegList saves = descriptor->CalleeSavedRegisters();
1471 // Restore registers.
1472 if (saves != 0) {
1473 for (int i = 0; i < Register::kNumRegisters; i++) {
1474 if (!((1 << i) & saves)) continue;
1475 __ pop(Register::from_code(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001477 }
1478
1479 if (descriptor->IsCFunctionCall()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1481 __ pop(ebp); // Pop caller's frame pointer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 } else if (frame()->needs_frame()) {
1483 // Canonicalize JSFunction return sites for now.
1484 if (return_label_.is_bound()) {
1485 __ jmp(&return_label_);
1486 return;
1487 } else {
1488 __ bind(&return_label_);
1489 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1490 __ pop(ebp); // Pop caller's frame pointer.
1491 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001492 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001493 size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
1494 // Might need ecx for scratch if pop_size is too big.
1495 DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
1496 __ Ret(static_cast<int>(pop_size), ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497}
1498
1499
1500void CodeGenerator::AssembleMove(InstructionOperand* source,
1501 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 // Dispatch on the source and destination operand kinds. Not all
1504 // combinations are possible.
1505 if (source->IsRegister()) {
1506 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1507 Register src = g.ToRegister(source);
1508 Operand dst = g.ToOperand(destination);
1509 __ mov(dst, src);
1510 } else if (source->IsStackSlot()) {
1511 DCHECK(destination->IsRegister() || destination->IsStackSlot());
1512 Operand src = g.ToOperand(source);
1513 if (destination->IsRegister()) {
1514 Register dst = g.ToRegister(destination);
1515 __ mov(dst, src);
1516 } else {
1517 Operand dst = g.ToOperand(destination);
1518 __ push(src);
1519 __ pop(dst);
1520 }
1521 } else if (source->IsConstant()) {
1522 Constant src_constant = g.ToConstant(source);
1523 if (src_constant.type() == Constant::kHeapObject) {
1524 Handle<HeapObject> src = src_constant.ToHeapObject();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001525 int offset;
1526 if (IsMaterializableFromFrame(src, &offset)) {
1527 if (destination->IsRegister()) {
1528 Register dst = g.ToRegister(destination);
1529 __ mov(dst, g.ToMaterializableOperand(offset));
1530 } else {
1531 DCHECK(destination->IsStackSlot());
1532 Operand dst = g.ToOperand(destination);
1533 __ push(g.ToMaterializableOperand(offset));
1534 __ pop(dst);
1535 }
1536 } else if (destination->IsRegister()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 Register dst = g.ToRegister(destination);
1538 __ LoadHeapObject(dst, src);
1539 } else {
1540 DCHECK(destination->IsStackSlot());
1541 Operand dst = g.ToOperand(destination);
1542 AllowDeferredHandleDereference embedding_raw_address;
1543 if (isolate()->heap()->InNewSpace(*src)) {
1544 __ PushHeapObject(src);
1545 __ pop(dst);
1546 } else {
1547 __ mov(dst, src);
1548 }
1549 }
1550 } else if (destination->IsRegister()) {
1551 Register dst = g.ToRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001552 __ Move(dst, g.ToImmediate(source));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 } else if (destination->IsStackSlot()) {
1554 Operand dst = g.ToOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001555 __ Move(dst, g.ToImmediate(source));
1556 } else if (src_constant.type() == Constant::kFloat32) {
1557 // TODO(turbofan): Can we do better here?
1558 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559 if (destination->IsDoubleRegister()) {
1560 XMMRegister dst = g.ToDoubleRegister(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001561 __ Move(dst, src);
1562 } else {
1563 DCHECK(destination->IsDoubleStackSlot());
1564 Operand dst = g.ToOperand(destination);
1565 __ Move(dst, Immediate(src));
1566 }
1567 } else {
1568 DCHECK_EQ(Constant::kFloat64, src_constant.type());
1569 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1570 uint32_t lower = static_cast<uint32_t>(src);
1571 uint32_t upper = static_cast<uint32_t>(src >> 32);
1572 if (destination->IsDoubleRegister()) {
1573 XMMRegister dst = g.ToDoubleRegister(destination);
1574 __ Move(dst, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575 } else {
1576 DCHECK(destination->IsDoubleStackSlot());
1577 Operand dst0 = g.ToOperand(destination);
1578 Operand dst1 = g.HighOperand(destination);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001579 __ Move(dst0, Immediate(lower));
1580 __ Move(dst1, Immediate(upper));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 }
1582 }
1583 } else if (source->IsDoubleRegister()) {
1584 XMMRegister src = g.ToDoubleRegister(source);
1585 if (destination->IsDoubleRegister()) {
1586 XMMRegister dst = g.ToDoubleRegister(destination);
1587 __ movaps(dst, src);
1588 } else {
1589 DCHECK(destination->IsDoubleStackSlot());
1590 Operand dst = g.ToOperand(destination);
1591 __ movsd(dst, src);
1592 }
1593 } else if (source->IsDoubleStackSlot()) {
1594 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1595 Operand src = g.ToOperand(source);
1596 if (destination->IsDoubleRegister()) {
1597 XMMRegister dst = g.ToDoubleRegister(destination);
1598 __ movsd(dst, src);
1599 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001600 Operand dst = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001601 __ movsd(kScratchDoubleReg, src);
1602 __ movsd(dst, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001603 }
1604 } else {
1605 UNREACHABLE();
1606 }
1607}
1608
1609
1610void CodeGenerator::AssembleSwap(InstructionOperand* source,
1611 InstructionOperand* destination) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001612 IA32OperandConverter g(this, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 // Dispatch on the source and destination operand kinds. Not all
1614 // combinations are possible.
1615 if (source->IsRegister() && destination->IsRegister()) {
1616 // Register-register.
1617 Register src = g.ToRegister(source);
1618 Register dst = g.ToRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001619 __ push(src);
1620 __ mov(src, dst);
1621 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001622 } else if (source->IsRegister() && destination->IsStackSlot()) {
1623 // Register-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001624 Register src = g.ToRegister(source);
1625 __ push(src);
1626 frame_access_state()->IncreaseSPDelta(1);
1627 Operand dst = g.ToOperand(destination);
1628 __ mov(src, dst);
1629 frame_access_state()->IncreaseSPDelta(-1);
1630 dst = g.ToOperand(destination);
1631 __ pop(dst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001632 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
1633 // Memory-memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 Operand dst1 = g.ToOperand(destination);
1635 __ push(dst1);
1636 frame_access_state()->IncreaseSPDelta(1);
1637 Operand src1 = g.ToOperand(source);
1638 __ push(src1);
1639 Operand dst2 = g.ToOperand(destination);
1640 __ pop(dst2);
1641 frame_access_state()->IncreaseSPDelta(-1);
1642 Operand src2 = g.ToOperand(source);
1643 __ pop(src2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001644 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 // XMM register-register swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001646 XMMRegister src = g.ToDoubleRegister(source);
1647 XMMRegister dst = g.ToDoubleRegister(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 __ movaps(kScratchDoubleReg, src);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 __ movaps(src, dst);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001650 __ movaps(dst, kScratchDoubleReg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001651 } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 // XMM register-memory swap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 XMMRegister reg = g.ToDoubleRegister(source);
1654 Operand other = g.ToOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 __ movsd(kScratchDoubleReg, other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001656 __ movsd(other, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001657 __ movaps(reg, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001658 } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
1659 // Double-width memory-to-memory.
1660 Operand src0 = g.ToOperand(source);
1661 Operand src1 = g.HighOperand(source);
1662 Operand dst0 = g.ToOperand(destination);
1663 Operand dst1 = g.HighOperand(destination);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001664 __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register.
1665 __ push(src0); // Then use stack to copy source to destination.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 __ pop(dst0);
1667 __ push(src1);
1668 __ pop(dst1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001669 __ movsd(src0, kScratchDoubleReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001670 } else {
1671 // No other combinations are possible.
1672 UNREACHABLE();
1673 }
1674}
1675
1676
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1678 for (size_t index = 0; index < target_count; ++index) {
1679 __ dd(targets[index]);
1680 }
1681}
1682
1683
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001684void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
1685
1686
1687void CodeGenerator::EnsureSpaceForLazyDeopt() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
1689 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001690 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001691
1692 int space_needed = Deoptimizer::patch_size();
1693 // Ensure that we have enough space after the previous lazy-bailout
1694 // instruction for patching the code here.
1695 int current_pc = masm()->pc_offset();
1696 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1697 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1698 __ Nop(padding_size);
1699 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001700}
1701
1702#undef __
1703
1704} // namespace compiler
1705} // namespace internal
1706} // namespace v8