blob: 6bacda0cb6dc3c9a2774cb1ffd577187d0571572 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +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
7#include "src/ast/scopes.h"
8#include "src/compiler/code-generator-impl.h"
9#include "src/compiler/gap-resolver.h"
10#include "src/compiler/node-matchers.h"
11#include "src/compiler/osr.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/frames.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/x87/assembler-x87.h"
14#include "src/x87/frames-x87.h"
15#include "src/x87/macro-assembler-x87.h"
16
17namespace v8 {
18namespace internal {
19namespace compiler {
20
21#define __ masm()->
22
23
24// Adds X87 specific methods for decoding operands.
25class X87OperandConverter : public InstructionOperandConverter {
26 public:
27 X87OperandConverter(CodeGenerator* gen, Instruction* instr)
28 : InstructionOperandConverter(gen, instr) {}
29
30 Operand InputOperand(size_t index, int extra = 0) {
31 return ToOperand(instr_->InputAt(index), extra);
32 }
33
34 Immediate InputImmediate(size_t index) {
35 return ToImmediate(instr_->InputAt(index));
36 }
37
38 Operand OutputOperand() { return ToOperand(instr_->Output()); }
39
40 Operand ToOperand(InstructionOperand* op, int extra = 0) {
41 if (op->IsRegister()) {
42 DCHECK(extra == 0);
43 return Operand(ToRegister(op));
44 }
Ben Murdochc5610432016-08-08 18:44:38 +010045 DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
Ben Murdochda12d292016-06-02 14:46:10 +010046 return SlotToOperand(AllocatedOperand::cast(op)->index(), extra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 }
48
Ben Murdochda12d292016-06-02 14:46:10 +010049 Operand SlotToOperand(int slot, int extra = 0) {
50 FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
51 return Operand(offset.from_stack_pointer() ? esp : ebp,
52 offset.offset() + extra);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 }
54
55 Operand HighOperand(InstructionOperand* op) {
Ben Murdochc5610432016-08-08 18:44:38 +010056 DCHECK(op->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 return ToOperand(op, kPointerSize);
58 }
59
60 Immediate ToImmediate(InstructionOperand* operand) {
61 Constant constant = ToConstant(operand);
Ben Murdochc5610432016-08-08 18:44:38 +010062 if (constant.type() == Constant::kInt32 &&
63 (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
Ben Murdoch61f157c2016-09-16 13:49:30 +010064 constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
Ben Murdochc5610432016-08-08 18:44:38 +010065 constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) {
66 return Immediate(reinterpret_cast<Address>(constant.ToInt32()),
67 constant.rmode());
68 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069 switch (constant.type()) {
70 case Constant::kInt32:
71 return Immediate(constant.ToInt32());
72 case Constant::kFloat32:
73 return Immediate(
74 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
75 case Constant::kFloat64:
76 return Immediate(
77 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
78 case Constant::kExternalReference:
79 return Immediate(constant.ToExternalReference());
80 case Constant::kHeapObject:
81 return Immediate(constant.ToHeapObject());
82 case Constant::kInt64:
83 break;
84 case Constant::kRpoNumber:
85 return Immediate::CodeRelativeOffset(ToLabel(operand));
86 }
87 UNREACHABLE();
88 return Immediate(-1);
89 }
90
91 static size_t NextOffset(size_t* offset) {
92 size_t i = *offset;
93 (*offset)++;
94 return i;
95 }
96
97 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
98 STATIC_ASSERT(0 == static_cast<int>(times_1));
99 STATIC_ASSERT(1 == static_cast<int>(times_2));
100 STATIC_ASSERT(2 == static_cast<int>(times_4));
101 STATIC_ASSERT(3 == static_cast<int>(times_8));
102 int scale = static_cast<int>(mode - one);
103 DCHECK(scale >= 0 && scale < 4);
104 return static_cast<ScaleFactor>(scale);
105 }
106
107 Operand MemoryOperand(size_t* offset) {
108 AddressingMode mode = AddressingModeField::decode(instr_->opcode());
109 switch (mode) {
110 case kMode_MR: {
111 Register base = InputRegister(NextOffset(offset));
112 int32_t disp = 0;
113 return Operand(base, disp);
114 }
115 case kMode_MRI: {
116 Register base = InputRegister(NextOffset(offset));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100117 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
118 return Operand(base, ctant.ToInt32(), ctant.rmode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 }
120 case kMode_MR1:
121 case kMode_MR2:
122 case kMode_MR4:
123 case kMode_MR8: {
124 Register base = InputRegister(NextOffset(offset));
125 Register index = InputRegister(NextOffset(offset));
126 ScaleFactor scale = ScaleFor(kMode_MR1, mode);
127 int32_t disp = 0;
128 return Operand(base, index, scale, disp);
129 }
130 case kMode_MR1I:
131 case kMode_MR2I:
132 case kMode_MR4I:
133 case kMode_MR8I: {
134 Register base = InputRegister(NextOffset(offset));
135 Register index = InputRegister(NextOffset(offset));
136 ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100137 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
138 return Operand(base, index, scale, ctant.ToInt32(), ctant.rmode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 }
140 case kMode_M1:
141 case kMode_M2:
142 case kMode_M4:
143 case kMode_M8: {
144 Register index = InputRegister(NextOffset(offset));
145 ScaleFactor scale = ScaleFor(kMode_M1, mode);
146 int32_t disp = 0;
147 return Operand(index, scale, disp);
148 }
149 case kMode_M1I:
150 case kMode_M2I:
151 case kMode_M4I:
152 case kMode_M8I: {
153 Register index = InputRegister(NextOffset(offset));
154 ScaleFactor scale = ScaleFor(kMode_M1I, mode);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100155 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
156 return Operand(index, scale, ctant.ToInt32(), ctant.rmode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 }
158 case kMode_MI: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100159 Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
160 return Operand(ctant.ToInt32(), ctant.rmode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 }
162 case kMode_None:
163 UNREACHABLE();
164 return Operand(no_reg, 0);
165 }
166 UNREACHABLE();
167 return Operand(no_reg, 0);
168 }
169
170 Operand MemoryOperand(size_t first_input = 0) {
171 return MemoryOperand(&first_input);
172 }
173};
174
175
176namespace {
177
178bool HasImmediateInput(Instruction* instr, size_t index) {
179 return instr->InputAt(index)->IsImmediate();
180}
181
182
183class OutOfLineLoadInteger final : public OutOfLineCode {
184 public:
185 OutOfLineLoadInteger(CodeGenerator* gen, Register result)
186 : OutOfLineCode(gen), result_(result) {}
187
188 void Generate() final { __ xor_(result_, result_); }
189
190 private:
191 Register const result_;
192};
193
194
195class OutOfLineLoadFloat final : public OutOfLineCode {
196 public:
197 OutOfLineLoadFloat(CodeGenerator* gen, X87Register result)
198 : OutOfLineCode(gen), result_(result) {}
199
200 void Generate() final {
201 DCHECK(result_.code() == 0);
202 USE(result_);
203 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
204 __ VerifyX87StackDepth(1);
205 }
206 __ fstp(0);
207 __ push(Immediate(0xffffffff));
208 __ push(Immediate(0x7fffffff));
209 __ fld_d(MemOperand(esp, 0));
210 __ lea(esp, Operand(esp, kDoubleSize));
211 }
212
213 private:
214 X87Register const result_;
215};
216
217
218class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
219 public:
220 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
221 X87Register input)
222 : OutOfLineCode(gen), result_(result), input_(input) {}
223
224 void Generate() final {
225 UNIMPLEMENTED();
226 USE(result_);
227 USE(input_);
228 }
229
230 private:
231 Register const result_;
232 X87Register const input_;
233};
234
235
236class OutOfLineRecordWrite final : public OutOfLineCode {
237 public:
238 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand,
239 Register value, Register scratch0, Register scratch1,
240 RecordWriteMode mode)
241 : OutOfLineCode(gen),
242 object_(object),
243 operand_(operand),
244 value_(value),
245 scratch0_(scratch0),
246 scratch1_(scratch1),
247 mode_(mode) {}
248
249 void Generate() final {
250 if (mode_ > RecordWriteMode::kValueIsPointer) {
251 __ JumpIfSmi(value_, exit());
252 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100253 __ CheckPageFlag(value_, scratch0_,
254 MemoryChunk::kPointersToHereAreInterestingMask, zero,
255 exit());
256 RememberedSetAction const remembered_set_action =
257 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
258 : OMIT_REMEMBERED_SET;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 SaveFPRegsMode const save_fp_mode =
260 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
261 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 remembered_set_action, save_fp_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 __ lea(scratch1_, operand_);
264 __ CallStub(&stub);
265 }
266
267 private:
268 Register const object_;
269 Operand const operand_;
270 Register const value_;
271 Register const scratch0_;
272 Register const scratch1_;
273 RecordWriteMode const mode_;
274};
275
276} // namespace
277
278
279#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \
280 do { \
281 auto result = i.OutputDoubleRegister(); \
282 auto offset = i.InputRegister(0); \
283 DCHECK(result.code() == 0); \
284 if (instr->InputAt(1)->IsRegister()) { \
285 __ cmp(offset, i.InputRegister(1)); \
286 } else { \
287 __ cmp(offset, i.InputImmediate(1)); \
288 } \
289 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
290 __ j(above_equal, ool->entry()); \
291 __ fstp(0); \
292 __ asm_instr(i.MemoryOperand(2)); \
293 __ bind(ool->exit()); \
294 } while (false)
295
296
297#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
298 do { \
299 auto result = i.OutputRegister(); \
300 auto offset = i.InputRegister(0); \
301 if (instr->InputAt(1)->IsRegister()) { \
302 __ cmp(offset, i.InputRegister(1)); \
303 } else { \
304 __ cmp(offset, i.InputImmediate(1)); \
305 } \
306 OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
307 __ j(above_equal, ool->entry()); \
308 __ asm_instr(result, i.MemoryOperand(2)); \
309 __ bind(ool->exit()); \
310 } while (false)
311
312
313#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \
314 do { \
315 auto offset = i.InputRegister(0); \
316 if (instr->InputAt(1)->IsRegister()) { \
317 __ cmp(offset, i.InputRegister(1)); \
318 } else { \
319 __ cmp(offset, i.InputImmediate(1)); \
320 } \
321 Label done; \
322 DCHECK(i.InputDoubleRegister(2).code() == 0); \
323 __ j(above_equal, &done, Label::kNear); \
324 __ asm_instr(i.MemoryOperand(3)); \
325 __ bind(&done); \
326 } while (false)
327
328
329#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
330 do { \
331 auto offset = i.InputRegister(0); \
332 if (instr->InputAt(1)->IsRegister()) { \
333 __ cmp(offset, i.InputRegister(1)); \
334 } else { \
335 __ cmp(offset, i.InputImmediate(1)); \
336 } \
337 Label done; \
338 __ j(above_equal, &done, Label::kNear); \
339 if (instr->InputAt(2)->IsRegister()) { \
340 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
341 } else { \
342 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
343 } \
344 __ bind(&done); \
345 } while (false)
346
Ben Murdochda12d292016-06-02 14:46:10 +0100347#define ASSEMBLE_COMPARE(asm_instr) \
348 do { \
349 if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
350 size_t index = 0; \
351 Operand left = i.MemoryOperand(&index); \
352 if (HasImmediateInput(instr, index)) { \
353 __ asm_instr(left, i.InputImmediate(index)); \
354 } else { \
355 __ asm_instr(left, i.InputRegister(index)); \
356 } \
357 } else { \
358 if (HasImmediateInput(instr, 1)) { \
359 if (instr->InputAt(0)->IsRegister()) { \
360 __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
361 } else { \
362 __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
363 } \
364 } else { \
365 if (instr->InputAt(1)->IsRegister()) { \
366 __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
367 } else { \
368 __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
369 } \
370 } \
371 } \
372 } while (0)
373
Ben Murdoch61f157c2016-09-16 13:49:30 +0100374#define ASSEMBLE_IEEE754_BINOP(name) \
375 do { \
376 /* Saves the esp into ebx */ \
377 __ push(ebx); \
378 __ mov(ebx, esp); \
379 /* Pass one double as argument on the stack. */ \
380 __ PrepareCallCFunction(4, eax); \
381 __ fstp(0); \
382 /* Load first operand from original stack */ \
383 __ fld_d(MemOperand(ebx, 4 + kDoubleSize)); \
384 /* Put first operand into stack for function call */ \
385 __ fstp_d(Operand(esp, 0 * kDoubleSize)); \
386 /* Load second operand from original stack */ \
387 __ fld_d(MemOperand(ebx, 4)); \
388 /* Put second operand into stack for function call */ \
389 __ fstp_d(Operand(esp, 1 * kDoubleSize)); \
390 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
391 4); \
392 /* Restore the ebx */ \
393 __ pop(ebx); \
394 /* Return value is in st(0) on x87. */ \
395 __ lea(esp, Operand(esp, 2 * kDoubleSize)); \
396 } while (false)
397
398#define ASSEMBLE_IEEE754_UNOP(name) \
399 do { \
400 /* Saves the esp into ebx */ \
401 __ push(ebx); \
402 __ mov(ebx, esp); \
403 /* Pass one double as argument on the stack. */ \
404 __ PrepareCallCFunction(2, eax); \
405 __ fstp(0); \
406 /* Load operand from original stack */ \
407 __ fld_d(MemOperand(ebx, 4)); \
408 /* Put operand into stack for function call */ \
409 __ fstp_d(Operand(esp, 0)); \
410 __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
411 2); \
412 /* Restore the ebx */ \
413 __ pop(ebx); \
414 /* Return value is in st(0) on x87. */ \
415 __ lea(esp, Operand(esp, kDoubleSize)); \
416 } while (false)
417
Ben Murdochda12d292016-06-02 14:46:10 +0100418void CodeGenerator::AssembleDeconstructFrame() {
419 __ mov(esp, ebp);
420 __ pop(ebp);
421}
422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
424 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
425 if (sp_slot_delta > 0) {
426 __ add(esp, Immediate(sp_slot_delta * kPointerSize));
427 }
428 frame_access_state()->SetFrameAccessToDefault();
429}
430
431
432void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
433 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
434 if (sp_slot_delta < 0) {
435 __ sub(esp, Immediate(-sp_slot_delta * kPointerSize));
436 frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
437 }
Ben Murdochda12d292016-06-02 14:46:10 +0100438 if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 __ mov(ebp, MemOperand(ebp, 0));
440 }
441 frame_access_state()->SetFrameAccessToSP();
442}
443
Ben Murdochda12d292016-06-02 14:46:10 +0100444void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
445 Register, Register,
446 Register) {
447 // There are not enough temp registers left on ia32 for a call instruction
448 // so we pick some scratch registers and save/restore them manually here.
449 int scratch_count = 3;
450 Register scratch1 = ebx;
451 Register scratch2 = ecx;
452 Register scratch3 = edx;
453 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
454 Label done;
455
456 // Check if current frame is an arguments adaptor frame.
457 __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset),
458 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
459 __ j(not_equal, &done, Label::kNear);
460
461 __ push(scratch1);
462 __ push(scratch2);
463 __ push(scratch3);
464
465 // Load arguments count from current arguments adaptor frame (note, it
466 // does not include receiver).
467 Register caller_args_count_reg = scratch1;
468 __ mov(caller_args_count_reg,
469 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
470 __ SmiUntag(caller_args_count_reg);
471
472 ParameterCount callee_args_count(args_reg);
473 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
474 scratch3, ReturnAddressState::kOnStack, scratch_count);
475 __ pop(scratch3);
476 __ pop(scratch2);
477 __ pop(scratch1);
478
479 __ bind(&done);
480}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481
482// Assembles an instruction after register allocation, producing machine code.
Ben Murdochc5610432016-08-08 18:44:38 +0100483CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
484 Instruction* instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 X87OperandConverter i(this, instr);
Ben Murdochda12d292016-06-02 14:46:10 +0100486 InstructionCode opcode = instr->opcode();
487 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488
Ben Murdochda12d292016-06-02 14:46:10 +0100489 switch (arch_opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 case kArchCallCodeObject: {
491 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
492 __ VerifyX87StackDepth(1);
493 }
494 __ fstp(0);
495 EnsureSpaceForLazyDeopt();
496 if (HasImmediateInput(instr, 0)) {
497 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
498 __ call(code, RelocInfo::CODE_TARGET);
499 } else {
500 Register reg = i.InputRegister(0);
501 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
502 __ call(reg);
503 }
504 RecordCallPosition(instr);
505 bool double_result =
Ben Murdochc5610432016-08-08 18:44:38 +0100506 instr->HasOutput() && instr->Output()->IsFPRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 if (double_result) {
508 __ lea(esp, Operand(esp, -kDoubleSize));
509 __ fstp_d(Operand(esp, 0));
510 }
511 __ fninit();
512 if (double_result) {
513 __ fld_d(Operand(esp, 0));
514 __ lea(esp, Operand(esp, kDoubleSize));
515 } else {
516 __ fld1();
517 }
518 frame_access_state()->ClearSPDelta();
519 break;
520 }
Ben Murdochda12d292016-06-02 14:46:10 +0100521 case kArchTailCallCodeObjectFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 case kArchTailCallCodeObject: {
523 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
524 __ VerifyX87StackDepth(1);
525 }
526 __ fstp(0);
527 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
528 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100529 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
530 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
531 no_reg, no_reg, no_reg);
532 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 if (HasImmediateInput(instr, 0)) {
534 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
535 __ jmp(code, RelocInfo::CODE_TARGET);
536 } else {
537 Register reg = i.InputRegister(0);
538 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag));
539 __ jmp(reg);
540 }
541 frame_access_state()->ClearSPDelta();
542 break;
543 }
Ben Murdochc5610432016-08-08 18:44:38 +0100544 case kArchTailCallAddress: {
545 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
546 AssembleDeconstructActivationRecord(stack_param_delta);
547 CHECK(!HasImmediateInput(instr, 0));
548 Register reg = i.InputRegister(0);
549 __ jmp(reg);
550 frame_access_state()->ClearSPDelta();
551 break;
552 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 case kArchCallJSFunction: {
554 EnsureSpaceForLazyDeopt();
555 Register func = i.InputRegister(0);
556 if (FLAG_debug_code) {
557 // Check the function's context matches the context argument.
558 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
559 __ Assert(equal, kWrongFunctionContext);
560 }
561 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
562 __ VerifyX87StackDepth(1);
563 }
564 __ fstp(0);
565 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
566 RecordCallPosition(instr);
567 bool double_result =
Ben Murdochc5610432016-08-08 18:44:38 +0100568 instr->HasOutput() && instr->Output()->IsFPRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 if (double_result) {
570 __ lea(esp, Operand(esp, -kDoubleSize));
571 __ fstp_d(Operand(esp, 0));
572 }
573 __ fninit();
574 if (double_result) {
575 __ fld_d(Operand(esp, 0));
576 __ lea(esp, Operand(esp, kDoubleSize));
577 } else {
578 __ fld1();
579 }
580 frame_access_state()->ClearSPDelta();
581 break;
582 }
Ben Murdochda12d292016-06-02 14:46:10 +0100583 case kArchTailCallJSFunctionFromJSFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 case kArchTailCallJSFunction: {
585 Register func = i.InputRegister(0);
586 if (FLAG_debug_code) {
587 // Check the function's context matches the context argument.
588 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
589 __ Assert(equal, kWrongFunctionContext);
590 }
591 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
592 __ VerifyX87StackDepth(1);
593 }
594 __ fstp(0);
595 int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
596 AssembleDeconstructActivationRecord(stack_param_delta);
Ben Murdochda12d292016-06-02 14:46:10 +0100597 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
598 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
599 no_reg, no_reg, no_reg);
600 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
602 frame_access_state()->ClearSPDelta();
603 break;
604 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 case kArchPrepareCallCFunction: {
606 // Frame alignment requires using FP-relative frame addressing.
607 frame_access_state()->SetFrameAccessToFP();
608 int const num_parameters = MiscField::decode(instr->opcode());
609 __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
610 break;
611 }
612 case kArchPrepareTailCall:
613 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
614 break;
615 case kArchCallCFunction: {
616 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
617 __ VerifyX87StackDepth(1);
618 }
619 __ fstp(0);
620 int const num_parameters = MiscField::decode(instr->opcode());
621 if (HasImmediateInput(instr, 0)) {
622 ExternalReference ref = i.InputExternalReference(0);
623 __ CallCFunction(ref, num_parameters);
624 } else {
625 Register func = i.InputRegister(0);
626 __ CallCFunction(func, num_parameters);
627 }
628 bool double_result =
Ben Murdochc5610432016-08-08 18:44:38 +0100629 instr->HasOutput() && instr->Output()->IsFPRegister();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 if (double_result) {
631 __ lea(esp, Operand(esp, -kDoubleSize));
632 __ fstp_d(Operand(esp, 0));
633 }
634 __ fninit();
635 if (double_result) {
636 __ fld_d(Operand(esp, 0));
637 __ lea(esp, Operand(esp, kDoubleSize));
638 } else {
639 __ fld1();
640 }
641 frame_access_state()->SetFrameAccessToDefault();
642 frame_access_state()->ClearSPDelta();
643 break;
644 }
645 case kArchJmp:
646 AssembleArchJump(i.InputRpo(0));
647 break;
648 case kArchLookupSwitch:
649 AssembleArchLookupSwitch(instr);
650 break;
651 case kArchTableSwitch:
652 AssembleArchTableSwitch(instr);
653 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100654 case kArchComment: {
655 Address comment_string = i.InputExternalReference(0).address();
656 __ RecordComment(reinterpret_cast<const char*>(comment_string));
657 break;
658 }
659 case kArchDebugBreak:
660 __ int3();
661 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 case kArchNop:
663 case kArchThrowTerminator:
664 // don't emit code for nops.
665 break;
666 case kArchDeoptimize: {
667 int deopt_state_id =
668 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
669 int double_register_param_count = 0;
670 int x87_layout = 0;
671 for (size_t i = 0; i < instr->InputCount(); i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100672 if (instr->InputAt(i)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000673 double_register_param_count++;
674 }
675 }
676 // Currently we use only one X87 register. If double_register_param_count
677 // is bigger than 1, it means duplicated double register is added to input
678 // of this instruction.
679 if (double_register_param_count > 0) {
680 x87_layout = (0 << 3) | 1;
681 }
682 // The layout of x87 register stack is loaded on the top of FPU register
683 // stack for deoptimization.
684 __ push(Immediate(x87_layout));
685 __ fild_s(MemOperand(esp, 0));
686 __ lea(esp, Operand(esp, kPointerSize));
687
688 Deoptimizer::BailoutType bailout_type =
689 Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
Ben Murdochc5610432016-08-08 18:44:38 +0100690 CodeGenResult result =
691 AssembleDeoptimizerCall(deopt_state_id, bailout_type);
692 if (result != kSuccess) return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000693 break;
694 }
695 case kArchRet:
696 AssembleReturn();
697 break;
698 case kArchFramePointer:
699 __ mov(i.OutputRegister(), ebp);
700 break;
701 case kArchStackPointer:
702 __ mov(i.OutputRegister(), esp);
703 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100704 case kArchParentFramePointer:
Ben Murdochda12d292016-06-02 14:46:10 +0100705 if (frame_access_state()->has_frame()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100706 __ mov(i.OutputRegister(), Operand(ebp, 0));
707 } else {
708 __ mov(i.OutputRegister(), ebp);
709 }
710 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711 case kArchTruncateDoubleToI: {
Ben Murdochc5610432016-08-08 18:44:38 +0100712 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 __ fld_d(i.InputOperand(0));
714 }
715 __ TruncateX87TOSToI(i.OutputRegister());
Ben Murdochc5610432016-08-08 18:44:38 +0100716 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717 __ fstp(0);
718 }
719 break;
720 }
721 case kArchStoreWithWriteBarrier: {
722 RecordWriteMode mode =
723 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
724 Register object = i.InputRegister(0);
725 size_t index = 0;
726 Operand operand = i.MemoryOperand(&index);
727 Register value = i.InputRegister(index);
728 Register scratch0 = i.TempRegister(0);
729 Register scratch1 = i.TempRegister(1);
730 auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value,
731 scratch0, scratch1, mode);
732 __ mov(operand, value);
733 __ CheckPageFlag(object, scratch0,
734 MemoryChunk::kPointersFromHereAreInterestingMask,
735 not_zero, ool->entry());
736 __ bind(ool->exit());
737 break;
738 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100739 case kArchStackSlot: {
740 FrameOffset offset =
741 frame_access_state()->GetFrameOffset(i.InputInt32(0));
742 Register base;
743 if (offset.from_stack_pointer()) {
744 base = esp;
745 } else {
746 base = ebp;
747 }
748 __ lea(i.OutputRegister(), Operand(base, offset.offset()));
749 break;
750 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100751 case kIeee754Float64Atan:
752 ASSEMBLE_IEEE754_UNOP(atan);
753 break;
754 case kIeee754Float64Atan2:
755 ASSEMBLE_IEEE754_BINOP(atan2);
756 break;
757 case kIeee754Float64Cbrt:
758 ASSEMBLE_IEEE754_UNOP(cbrt);
759 break;
760 case kIeee754Float64Cos:
761 __ X87SetFPUCW(0x027F);
762 ASSEMBLE_IEEE754_UNOP(cos);
763 __ X87SetFPUCW(0x037F);
764 break;
765 case kIeee754Float64Expm1:
766 __ X87SetFPUCW(0x027F);
767 ASSEMBLE_IEEE754_UNOP(expm1);
768 __ X87SetFPUCW(0x037F);
769 break;
770 case kIeee754Float64Exp:
771 ASSEMBLE_IEEE754_UNOP(exp);
772 break;
773 case kIeee754Float64Atanh:
774 ASSEMBLE_IEEE754_UNOP(atanh);
775 break;
776 case kIeee754Float64Log:
777 ASSEMBLE_IEEE754_UNOP(log);
778 break;
779 case kIeee754Float64Log1p:
780 ASSEMBLE_IEEE754_UNOP(log1p);
781 break;
782 case kIeee754Float64Log2:
783 ASSEMBLE_IEEE754_UNOP(log2);
784 break;
785 case kIeee754Float64Log10:
786 ASSEMBLE_IEEE754_UNOP(log10);
787 break;
788 case kIeee754Float64Sin:
789 __ X87SetFPUCW(0x027F);
790 ASSEMBLE_IEEE754_UNOP(sin);
791 __ X87SetFPUCW(0x037F);
792 break;
793 case kIeee754Float64Tan:
794 __ X87SetFPUCW(0x027F);
795 ASSEMBLE_IEEE754_UNOP(tan);
796 __ X87SetFPUCW(0x037F);
797 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 case kX87Add:
799 if (HasImmediateInput(instr, 1)) {
800 __ add(i.InputOperand(0), i.InputImmediate(1));
801 } else {
802 __ add(i.InputRegister(0), i.InputOperand(1));
803 }
804 break;
805 case kX87And:
806 if (HasImmediateInput(instr, 1)) {
807 __ and_(i.InputOperand(0), i.InputImmediate(1));
808 } else {
809 __ and_(i.InputRegister(0), i.InputOperand(1));
810 }
811 break;
812 case kX87Cmp:
Ben Murdochda12d292016-06-02 14:46:10 +0100813 ASSEMBLE_COMPARE(cmp);
814 break;
815 case kX87Cmp16:
816 ASSEMBLE_COMPARE(cmpw);
817 break;
818 case kX87Cmp8:
819 ASSEMBLE_COMPARE(cmpb);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000820 break;
821 case kX87Test:
Ben Murdochda12d292016-06-02 14:46:10 +0100822 ASSEMBLE_COMPARE(test);
823 break;
824 case kX87Test16:
825 ASSEMBLE_COMPARE(test_w);
826 break;
827 case kX87Test8:
828 ASSEMBLE_COMPARE(test_b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 break;
830 case kX87Imul:
831 if (HasImmediateInput(instr, 1)) {
832 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
833 } else {
834 __ imul(i.OutputRegister(), i.InputOperand(1));
835 }
836 break;
837 case kX87ImulHigh:
838 __ imul(i.InputRegister(1));
839 break;
840 case kX87UmulHigh:
841 __ mul(i.InputRegister(1));
842 break;
843 case kX87Idiv:
844 __ cdq();
845 __ idiv(i.InputOperand(1));
846 break;
847 case kX87Udiv:
848 __ Move(edx, Immediate(0));
849 __ div(i.InputOperand(1));
850 break;
851 case kX87Not:
852 __ not_(i.OutputOperand());
853 break;
854 case kX87Neg:
855 __ neg(i.OutputOperand());
856 break;
857 case kX87Or:
858 if (HasImmediateInput(instr, 1)) {
859 __ or_(i.InputOperand(0), i.InputImmediate(1));
860 } else {
861 __ or_(i.InputRegister(0), i.InputOperand(1));
862 }
863 break;
864 case kX87Xor:
865 if (HasImmediateInput(instr, 1)) {
866 __ xor_(i.InputOperand(0), i.InputImmediate(1));
867 } else {
868 __ xor_(i.InputRegister(0), i.InputOperand(1));
869 }
870 break;
871 case kX87Sub:
872 if (HasImmediateInput(instr, 1)) {
873 __ sub(i.InputOperand(0), i.InputImmediate(1));
874 } else {
875 __ sub(i.InputRegister(0), i.InputOperand(1));
876 }
877 break;
878 case kX87Shl:
879 if (HasImmediateInput(instr, 1)) {
880 __ shl(i.OutputOperand(), i.InputInt5(1));
881 } else {
882 __ shl_cl(i.OutputOperand());
883 }
884 break;
885 case kX87Shr:
886 if (HasImmediateInput(instr, 1)) {
887 __ shr(i.OutputOperand(), i.InputInt5(1));
888 } else {
889 __ shr_cl(i.OutputOperand());
890 }
891 break;
892 case kX87Sar:
893 if (HasImmediateInput(instr, 1)) {
894 __ sar(i.OutputOperand(), i.InputInt5(1));
895 } else {
896 __ sar_cl(i.OutputOperand());
897 }
898 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100899 case kX87AddPair: {
900 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
901 // i.InputRegister(1) ... left high word.
902 // i.InputRegister(2) ... right low word.
903 // i.InputRegister(3) ... right high word.
904 bool use_temp = false;
905 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
906 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
907 // We cannot write to the output register directly, because it would
908 // overwrite an input for adc. We have to use the temp register.
909 use_temp = true;
910 __ Move(i.TempRegister(0), i.InputRegister(0));
911 __ add(i.TempRegister(0), i.InputRegister(2));
912 } else {
913 __ add(i.OutputRegister(0), i.InputRegister(2));
914 }
915 __ adc(i.InputRegister(1), Operand(i.InputRegister(3)));
916 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
917 __ Move(i.OutputRegister(1), i.InputRegister(1));
918 }
919 if (use_temp) {
920 __ Move(i.OutputRegister(0), i.TempRegister(0));
921 }
922 break;
923 }
924 case kX87SubPair: {
925 // i.OutputRegister(0) == i.InputRegister(0) ... left low word.
926 // i.InputRegister(1) ... left high word.
927 // i.InputRegister(2) ... right low word.
928 // i.InputRegister(3) ... right high word.
929 bool use_temp = false;
930 if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
931 i.OutputRegister(0).code() == i.InputRegister(3).code()) {
932 // We cannot write to the output register directly, because it would
933 // overwrite an input for adc. We have to use the temp register.
934 use_temp = true;
935 __ Move(i.TempRegister(0), i.InputRegister(0));
936 __ sub(i.TempRegister(0), i.InputRegister(2));
937 } else {
938 __ sub(i.OutputRegister(0), i.InputRegister(2));
939 }
940 __ sbb(i.InputRegister(1), Operand(i.InputRegister(3)));
941 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
942 __ Move(i.OutputRegister(1), i.InputRegister(1));
943 }
944 if (use_temp) {
945 __ Move(i.OutputRegister(0), i.TempRegister(0));
946 }
947 break;
948 }
949 case kX87MulPair: {
950 __ imul(i.OutputRegister(1), i.InputOperand(0));
951 __ mov(i.TempRegister(0), i.InputOperand(1));
952 __ imul(i.TempRegister(0), i.InputOperand(2));
953 __ add(i.OutputRegister(1), i.TempRegister(0));
954 __ mov(i.OutputRegister(0), i.InputOperand(0));
955 // Multiplies the low words and stores them in eax and edx.
956 __ mul(i.InputRegister(2));
957 __ add(i.OutputRegister(1), i.TempRegister(0));
958
959 break;
960 }
961 case kX87ShlPair:
962 if (HasImmediateInput(instr, 2)) {
963 __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
964 } else {
965 // Shift has been loaded into CL by the register allocator.
966 __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0));
967 }
968 break;
969 case kX87ShrPair:
970 if (HasImmediateInput(instr, 2)) {
971 __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
972 } else {
973 // Shift has been loaded into CL by the register allocator.
974 __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0));
975 }
976 break;
977 case kX87SarPair:
978 if (HasImmediateInput(instr, 2)) {
979 __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
980 } else {
981 // Shift has been loaded into CL by the register allocator.
982 __ SarPair_cl(i.InputRegister(1), i.InputRegister(0));
983 }
984 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 case kX87Ror:
986 if (HasImmediateInput(instr, 1)) {
987 __ ror(i.OutputOperand(), i.InputInt5(1));
988 } else {
989 __ ror_cl(i.OutputOperand());
990 }
991 break;
992 case kX87Lzcnt:
993 __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
994 break;
995 case kX87Popcnt:
996 __ Popcnt(i.OutputRegister(), i.InputOperand(0));
997 break;
998 case kX87LoadFloat64Constant: {
999 InstructionOperand* source = instr->InputAt(0);
1000 InstructionOperand* destination = instr->Output();
1001 DCHECK(source->IsConstant());
1002 X87OperandConverter g(this, nullptr);
1003 Constant src_constant = g.ToConstant(source);
1004
1005 DCHECK_EQ(Constant::kFloat64, src_constant.type());
1006 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
1007 uint32_t lower = static_cast<uint32_t>(src);
1008 uint32_t upper = static_cast<uint32_t>(src >> 32);
Ben Murdochc5610432016-08-08 18:44:38 +01001009 if (destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001010 __ sub(esp, Immediate(kDoubleSize));
1011 __ mov(MemOperand(esp, 0), Immediate(lower));
1012 __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
1013 __ fstp(0);
1014 __ fld_d(MemOperand(esp, 0));
1015 __ add(esp, Immediate(kDoubleSize));
1016 } else {
1017 UNREACHABLE();
1018 }
1019 break;
1020 }
1021 case kX87Float32Cmp: {
1022 __ fld_s(MemOperand(esp, kFloatSize));
1023 __ fld_s(MemOperand(esp, 0));
1024 __ FCmp();
1025 __ lea(esp, Operand(esp, 2 * kFloatSize));
1026 break;
1027 }
1028 case kX87Float32Add: {
1029 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1030 __ VerifyX87StackDepth(1);
1031 }
1032 __ X87SetFPUCW(0x027F);
1033 __ fstp(0);
1034 __ fld_s(MemOperand(esp, 0));
1035 __ fld_s(MemOperand(esp, kFloatSize));
1036 __ faddp();
1037 // Clear stack.
1038 __ lea(esp, Operand(esp, 2 * kFloatSize));
1039 // Restore the default value of control word.
1040 __ X87SetFPUCW(0x037F);
1041 break;
1042 }
1043 case kX87Float32Sub: {
1044 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1045 __ VerifyX87StackDepth(1);
1046 }
1047 __ X87SetFPUCW(0x027F);
1048 __ fstp(0);
1049 __ fld_s(MemOperand(esp, kFloatSize));
1050 __ fld_s(MemOperand(esp, 0));
1051 __ fsubp();
1052 // Clear stack.
1053 __ lea(esp, Operand(esp, 2 * kFloatSize));
1054 // Restore the default value of control word.
1055 __ X87SetFPUCW(0x037F);
1056 break;
1057 }
1058 case kX87Float32Mul: {
1059 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1060 __ VerifyX87StackDepth(1);
1061 }
1062 __ X87SetFPUCW(0x027F);
1063 __ fstp(0);
1064 __ fld_s(MemOperand(esp, kFloatSize));
1065 __ fld_s(MemOperand(esp, 0));
1066 __ fmulp();
1067 // Clear stack.
1068 __ lea(esp, Operand(esp, 2 * kFloatSize));
1069 // Restore the default value of control word.
1070 __ X87SetFPUCW(0x037F);
1071 break;
1072 }
1073 case kX87Float32Div: {
1074 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1075 __ VerifyX87StackDepth(1);
1076 }
1077 __ X87SetFPUCW(0x027F);
1078 __ fstp(0);
1079 __ fld_s(MemOperand(esp, kFloatSize));
1080 __ fld_s(MemOperand(esp, 0));
1081 __ fdivp();
1082 // Clear stack.
1083 __ lea(esp, Operand(esp, 2 * kFloatSize));
1084 // Restore the default value of control word.
1085 __ X87SetFPUCW(0x037F);
1086 break;
1087 }
1088 case kX87Float32Max: {
1089 Label check_nan_left, check_zero, return_left, return_right;
1090 Condition condition = below;
1091 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1092 __ VerifyX87StackDepth(1);
1093 }
1094 __ fstp(0);
1095 __ fld_s(MemOperand(esp, kFloatSize));
1096 __ fld_s(MemOperand(esp, 0));
1097 __ fld(1);
1098 __ fld(1);
1099 __ FCmp();
1100
1101 // At least one NaN.
1102 // Return the second operands if one of the two operands is NaN
1103 __ j(parity_even, &return_right, Label::kNear);
1104 __ j(equal, &check_zero, Label::kNear); // left == right.
1105 __ j(condition, &return_left, Label::kNear);
1106 __ jmp(&return_right, Label::kNear);
1107
1108 __ bind(&check_zero);
1109 __ fld(0);
1110 __ fldz();
1111 __ FCmp();
1112 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1113
1114 __ fadd(1);
1115 __ jmp(&return_left, Label::kNear);
1116
1117 __ bind(&return_right);
1118 __ fxch();
1119
1120 __ bind(&return_left);
1121 __ fstp(0);
1122 __ lea(esp, Operand(esp, 2 * kFloatSize));
1123 break;
1124 }
1125 case kX87Float32Min: {
1126 Label check_nan_left, check_zero, return_left, return_right;
1127 Condition condition = above;
1128 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1129 __ VerifyX87StackDepth(1);
1130 }
1131 __ fstp(0);
1132 __ fld_s(MemOperand(esp, kFloatSize));
1133 __ fld_s(MemOperand(esp, 0));
1134 __ fld(1);
1135 __ fld(1);
1136 __ FCmp();
1137 // At least one NaN.
1138 // Return the second operands if one of the two operands is NaN
1139 __ j(parity_even, &return_right, Label::kNear);
1140 __ j(equal, &check_zero, Label::kNear); // left == right.
1141 __ j(condition, &return_left, Label::kNear);
1142 __ jmp(&return_right, Label::kNear);
1143
1144 __ bind(&check_zero);
1145 __ fld(0);
1146 __ fldz();
1147 __ FCmp();
1148 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1149 // At this point, both left and right are either 0 or -0.
1150 // Push st0 and st1 to stack, then pop them to temp registers and OR them,
1151 // load it to left.
1152 __ push(eax);
1153 __ fld(1);
1154 __ fld(1);
1155 __ sub(esp, Immediate(2 * kPointerSize));
1156 __ fstp_s(MemOperand(esp, 0));
1157 __ fstp_s(MemOperand(esp, kPointerSize));
1158 __ pop(eax);
1159 __ xor_(MemOperand(esp, 0), eax);
1160 __ fstp(0);
1161 __ fld_s(MemOperand(esp, 0));
1162 __ pop(eax); // restore esp
1163 __ pop(eax); // restore esp
1164 __ jmp(&return_left, Label::kNear);
1165
1166
1167 __ bind(&return_right);
1168 __ fxch();
1169
1170 __ bind(&return_left);
1171 __ fstp(0);
1172 __ lea(esp, Operand(esp, 2 * kFloatSize));
1173 break;
1174 }
1175 case kX87Float32Sqrt: {
1176 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1177 __ VerifyX87StackDepth(1);
1178 }
1179 __ fstp(0);
1180 __ fld_s(MemOperand(esp, 0));
1181 __ fsqrt();
1182 __ lea(esp, Operand(esp, kFloatSize));
1183 break;
1184 }
1185 case kX87Float32Abs: {
1186 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1187 __ VerifyX87StackDepth(1);
1188 }
1189 __ fstp(0);
1190 __ fld_s(MemOperand(esp, 0));
1191 __ fabs();
1192 __ lea(esp, Operand(esp, kFloatSize));
1193 break;
1194 }
1195 case kX87Float32Round: {
1196 RoundingMode mode =
1197 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
1198 // Set the correct round mode in x87 control register
1199 __ X87SetRC((mode << 10));
1200
Ben Murdochc5610432016-08-08 18:44:38 +01001201 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 InstructionOperand* input = instr->InputAt(0);
1203 USE(input);
Ben Murdochc5610432016-08-08 18:44:38 +01001204 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1206 __ VerifyX87StackDepth(1);
1207 }
1208 __ fstp(0);
1209 __ fld_s(i.InputOperand(0));
1210 }
1211 __ frndint();
1212 __ X87SetRC(0x0000);
1213 break;
1214 }
1215 case kX87Float64Add: {
1216 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1217 __ VerifyX87StackDepth(1);
1218 }
1219 __ X87SetFPUCW(0x027F);
1220 __ fstp(0);
1221 __ fld_d(MemOperand(esp, 0));
1222 __ fld_d(MemOperand(esp, kDoubleSize));
1223 __ faddp();
1224 // Clear stack.
1225 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1226 // Restore the default value of control word.
1227 __ X87SetFPUCW(0x037F);
1228 break;
1229 }
1230 case kX87Float64Sub: {
1231 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1232 __ VerifyX87StackDepth(1);
1233 }
1234 __ X87SetFPUCW(0x027F);
1235 __ fstp(0);
1236 __ fld_d(MemOperand(esp, kDoubleSize));
1237 __ fsub_d(MemOperand(esp, 0));
1238 // Clear stack.
1239 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1240 // Restore the default value of control word.
1241 __ X87SetFPUCW(0x037F);
1242 break;
1243 }
1244 case kX87Float64Mul: {
1245 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1246 __ VerifyX87StackDepth(1);
1247 }
1248 __ X87SetFPUCW(0x027F);
1249 __ fstp(0);
1250 __ fld_d(MemOperand(esp, kDoubleSize));
1251 __ fmul_d(MemOperand(esp, 0));
1252 // Clear stack.
1253 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1254 // Restore the default value of control word.
1255 __ X87SetFPUCW(0x037F);
1256 break;
1257 }
1258 case kX87Float64Div: {
1259 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1260 __ VerifyX87StackDepth(1);
1261 }
1262 __ X87SetFPUCW(0x027F);
1263 __ fstp(0);
1264 __ fld_d(MemOperand(esp, kDoubleSize));
1265 __ fdiv_d(MemOperand(esp, 0));
1266 // Clear stack.
1267 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1268 // Restore the default value of control word.
1269 __ X87SetFPUCW(0x037F);
1270 break;
1271 }
1272 case kX87Float64Mod: {
1273 FrameScope frame_scope(&masm_, StackFrame::MANUAL);
1274 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1275 __ VerifyX87StackDepth(1);
1276 }
1277 __ mov(eax, esp);
1278 __ PrepareCallCFunction(4, eax);
1279 __ fstp(0);
1280 __ fld_d(MemOperand(eax, 0));
1281 __ fstp_d(Operand(esp, 1 * kDoubleSize));
1282 __ fld_d(MemOperand(eax, kDoubleSize));
1283 __ fstp_d(Operand(esp, 0));
1284 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
1285 4);
1286 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1287 break;
1288 }
1289 case kX87Float64Max: {
1290 Label check_zero, return_left, return_right;
1291 Condition condition = below;
1292 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1293 __ VerifyX87StackDepth(1);
1294 }
1295 __ fstp(0);
1296 __ fld_d(MemOperand(esp, kDoubleSize));
1297 __ fld_d(MemOperand(esp, 0));
1298 __ fld(1);
1299 __ fld(1);
1300 __ FCmp();
1301 __ j(parity_even, &return_right,
1302 Label::kNear); // At least one NaN, Return right.
1303 __ j(equal, &check_zero, Label::kNear); // left == right.
1304 __ j(condition, &return_left, Label::kNear);
1305 __ jmp(&return_right, Label::kNear);
1306
1307 __ bind(&check_zero);
1308 __ fld(0);
1309 __ fldz();
1310 __ FCmp();
1311 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1312
1313 __ bind(&return_right);
1314 __ fxch();
1315
1316 __ bind(&return_left);
1317 __ fstp(0);
1318 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1319 break;
1320 }
1321 case kX87Float64Min: {
1322 Label check_zero, return_left, return_right;
1323 Condition condition = above;
1324 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1325 __ VerifyX87StackDepth(1);
1326 }
1327 __ fstp(0);
1328 __ fld_d(MemOperand(esp, kDoubleSize));
1329 __ fld_d(MemOperand(esp, 0));
1330 __ fld(1);
1331 __ fld(1);
1332 __ FCmp();
1333 __ j(parity_even, &return_right,
1334 Label::kNear); // At least one NaN, return right value.
1335 __ j(equal, &check_zero, Label::kNear); // left == right.
1336 __ j(condition, &return_left, Label::kNear);
1337 __ jmp(&return_right, Label::kNear);
1338
1339 __ bind(&check_zero);
1340 __ fld(0);
1341 __ fldz();
1342 __ FCmp();
1343 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1344
1345 __ bind(&return_right);
1346 __ fxch();
1347
1348 __ bind(&return_left);
1349 __ fstp(0);
1350 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1351 break;
1352 }
1353 case kX87Float64Abs: {
1354 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1355 __ VerifyX87StackDepth(1);
1356 }
1357 __ fstp(0);
1358 __ fld_d(MemOperand(esp, 0));
1359 __ fabs();
1360 __ lea(esp, Operand(esp, kDoubleSize));
1361 break;
1362 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001363 case kX87Int32ToFloat32: {
1364 InstructionOperand* input = instr->InputAt(0);
1365 DCHECK(input->IsRegister() || input->IsStackSlot());
1366 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1367 __ VerifyX87StackDepth(1);
1368 }
1369 __ fstp(0);
1370 if (input->IsRegister()) {
1371 Register input_reg = i.InputRegister(0);
1372 __ push(input_reg);
1373 __ fild_s(Operand(esp, 0));
1374 __ pop(input_reg);
1375 } else {
1376 __ fild_s(i.InputOperand(0));
1377 }
1378 break;
1379 }
1380 case kX87Uint32ToFloat32: {
1381 InstructionOperand* input = instr->InputAt(0);
1382 DCHECK(input->IsRegister() || input->IsStackSlot());
1383 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1384 __ VerifyX87StackDepth(1);
1385 }
1386 __ fstp(0);
1387 Label msb_set_src;
1388 Label jmp_return;
1389 // Put input integer into eax(tmporarilly)
1390 __ push(eax);
1391 if (input->IsRegister())
1392 __ mov(eax, i.InputRegister(0));
1393 else
1394 __ mov(eax, i.InputOperand(0));
1395
1396 __ test(eax, eax);
1397 __ j(sign, &msb_set_src, Label::kNear);
1398 __ push(eax);
1399 __ fild_s(Operand(esp, 0));
1400 __ pop(eax);
1401
1402 __ jmp(&jmp_return, Label::kNear);
1403 __ bind(&msb_set_src);
1404 // Need another temp reg
1405 __ push(ebx);
1406 __ mov(ebx, eax);
1407 __ shr(eax, 1);
1408 // Recover the least significant bit to avoid rounding errors.
1409 __ and_(ebx, Immediate(1));
1410 __ or_(eax, ebx);
1411 __ push(eax);
1412 __ fild_s(Operand(esp, 0));
1413 __ pop(eax);
1414 __ fld(0);
1415 __ faddp();
1416 // Restore the ebx
1417 __ pop(ebx);
1418 __ bind(&jmp_return);
1419 // Restore the eax
1420 __ pop(eax);
1421 break;
1422 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 case kX87Int32ToFloat64: {
1424 InstructionOperand* input = instr->InputAt(0);
1425 DCHECK(input->IsRegister() || input->IsStackSlot());
1426 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1427 __ VerifyX87StackDepth(1);
1428 }
1429 __ fstp(0);
1430 if (input->IsRegister()) {
1431 Register input_reg = i.InputRegister(0);
1432 __ push(input_reg);
1433 __ fild_s(Operand(esp, 0));
1434 __ pop(input_reg);
1435 } else {
1436 __ fild_s(i.InputOperand(0));
1437 }
1438 break;
1439 }
1440 case kX87Float32ToFloat64: {
1441 InstructionOperand* input = instr->InputAt(0);
Ben Murdochc5610432016-08-08 18:44:38 +01001442 if (input->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443 __ sub(esp, Immediate(kDoubleSize));
Ben Murdochda12d292016-06-02 14:46:10 +01001444 __ fstp_s(MemOperand(esp, 0));
1445 __ fld_s(MemOperand(esp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 __ add(esp, Immediate(kDoubleSize));
1447 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001448 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1450 __ VerifyX87StackDepth(1);
1451 }
1452 __ fstp(0);
1453 __ fld_s(i.InputOperand(0));
1454 }
1455 break;
1456 }
1457 case kX87Uint32ToFloat64: {
1458 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1459 __ VerifyX87StackDepth(1);
1460 }
1461 __ fstp(0);
1462 __ LoadUint32NoSSE2(i.InputRegister(0));
1463 break;
1464 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001465 case kX87Float32ToInt32: {
Ben Murdochc5610432016-08-08 18:44:38 +01001466 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001467 __ fld_s(i.InputOperand(0));
1468 }
1469 __ TruncateX87TOSToI(i.OutputRegister(0));
Ben Murdochc5610432016-08-08 18:44:38 +01001470 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001471 __ fstp(0);
1472 }
1473 break;
1474 }
1475 case kX87Float32ToUint32: {
Ben Murdochc5610432016-08-08 18:44:38 +01001476 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001477 __ fld_s(i.InputOperand(0));
1478 }
1479 Label success;
1480 __ TruncateX87TOSToI(i.OutputRegister(0));
1481 __ test(i.OutputRegister(0), i.OutputRegister(0));
1482 __ j(positive, &success);
1483 __ push(Immediate(INT32_MIN));
1484 __ fild_s(Operand(esp, 0));
1485 __ lea(esp, Operand(esp, kPointerSize));
1486 __ faddp();
1487 __ TruncateX87TOSToI(i.OutputRegister(0));
1488 __ or_(i.OutputRegister(0), Immediate(0x80000000));
1489 __ bind(&success);
Ben Murdochc5610432016-08-08 18:44:38 +01001490 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001491 __ fstp(0);
1492 }
1493 break;
1494 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495 case kX87Float64ToInt32: {
Ben Murdochc5610432016-08-08 18:44:38 +01001496 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497 __ fld_d(i.InputOperand(0));
1498 }
1499 __ TruncateX87TOSToI(i.OutputRegister(0));
Ben Murdochc5610432016-08-08 18:44:38 +01001500 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 __ fstp(0);
1502 }
1503 break;
1504 }
1505 case kX87Float64ToFloat32: {
1506 InstructionOperand* input = instr->InputAt(0);
Ben Murdochc5610432016-08-08 18:44:38 +01001507 if (input->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 __ sub(esp, Immediate(kDoubleSize));
1509 __ fstp_s(MemOperand(esp, 0));
1510 __ fld_s(MemOperand(esp, 0));
1511 __ add(esp, Immediate(kDoubleSize));
1512 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001513 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1515 __ VerifyX87StackDepth(1);
1516 }
1517 __ fstp(0);
1518 __ fld_d(i.InputOperand(0));
1519 __ sub(esp, Immediate(kDoubleSize));
1520 __ fstp_s(MemOperand(esp, 0));
1521 __ fld_s(MemOperand(esp, 0));
1522 __ add(esp, Immediate(kDoubleSize));
1523 }
1524 break;
1525 }
1526 case kX87Float64ToUint32: {
1527 __ push_imm32(-2147483648);
Ben Murdochc5610432016-08-08 18:44:38 +01001528 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 __ fld_d(i.InputOperand(0));
1530 }
1531 __ fild_s(Operand(esp, 0));
Ben Murdochda12d292016-06-02 14:46:10 +01001532 __ fld(1);
1533 __ faddp();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534 __ TruncateX87TOSToI(i.OutputRegister(0));
1535 __ add(esp, Immediate(kInt32Size));
1536 __ add(i.OutputRegister(), Immediate(0x80000000));
Ben Murdochda12d292016-06-02 14:46:10 +01001537 __ fstp(0);
Ben Murdochc5610432016-08-08 18:44:38 +01001538 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001539 __ fstp(0);
1540 }
1541 break;
1542 }
1543 case kX87Float64ExtractHighWord32: {
Ben Murdochc5610432016-08-08 18:44:38 +01001544 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 __ sub(esp, Immediate(kDoubleSize));
1546 __ fst_d(MemOperand(esp, 0));
1547 __ mov(i.OutputRegister(), MemOperand(esp, kDoubleSize / 2));
1548 __ add(esp, Immediate(kDoubleSize));
1549 } else {
1550 InstructionOperand* input = instr->InputAt(0);
1551 USE(input);
Ben Murdochc5610432016-08-08 18:44:38 +01001552 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001553 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
1554 }
1555 break;
1556 }
1557 case kX87Float64ExtractLowWord32: {
Ben Murdochc5610432016-08-08 18:44:38 +01001558 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 __ sub(esp, Immediate(kDoubleSize));
1560 __ fst_d(MemOperand(esp, 0));
1561 __ mov(i.OutputRegister(), MemOperand(esp, 0));
1562 __ add(esp, Immediate(kDoubleSize));
1563 } else {
1564 InstructionOperand* input = instr->InputAt(0);
1565 USE(input);
Ben Murdochc5610432016-08-08 18:44:38 +01001566 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001567 __ mov(i.OutputRegister(), i.InputOperand(0));
1568 }
1569 break;
1570 }
1571 case kX87Float64InsertHighWord32: {
1572 __ sub(esp, Immediate(kDoubleSize));
1573 __ fstp_d(MemOperand(esp, 0));
1574 __ mov(MemOperand(esp, kDoubleSize / 2), i.InputRegister(1));
1575 __ fld_d(MemOperand(esp, 0));
1576 __ add(esp, Immediate(kDoubleSize));
1577 break;
1578 }
1579 case kX87Float64InsertLowWord32: {
1580 __ sub(esp, Immediate(kDoubleSize));
1581 __ fstp_d(MemOperand(esp, 0));
1582 __ mov(MemOperand(esp, 0), i.InputRegister(1));
1583 __ fld_d(MemOperand(esp, 0));
1584 __ add(esp, Immediate(kDoubleSize));
1585 break;
1586 }
1587 case kX87Float64Sqrt: {
1588 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1589 __ VerifyX87StackDepth(1);
1590 }
1591 __ X87SetFPUCW(0x027F);
1592 __ fstp(0);
1593 __ fld_d(MemOperand(esp, 0));
1594 __ fsqrt();
1595 __ lea(esp, Operand(esp, kDoubleSize));
1596 __ X87SetFPUCW(0x037F);
1597 break;
1598 }
1599 case kX87Float64Round: {
1600 RoundingMode mode =
1601 static_cast<RoundingMode>(MiscField::decode(instr->opcode()));
1602 // Set the correct round mode in x87 control register
1603 __ X87SetRC((mode << 10));
1604
Ben Murdochc5610432016-08-08 18:44:38 +01001605 if (!instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001606 InstructionOperand* input = instr->InputAt(0);
1607 USE(input);
Ben Murdochc5610432016-08-08 18:44:38 +01001608 DCHECK(input->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001609 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1610 __ VerifyX87StackDepth(1);
1611 }
1612 __ fstp(0);
1613 __ fld_d(i.InputOperand(0));
1614 }
1615 __ frndint();
1616 __ X87SetRC(0x0000);
1617 break;
1618 }
1619 case kX87Float64Cmp: {
1620 __ fld_d(MemOperand(esp, kDoubleSize));
1621 __ fld_d(MemOperand(esp, 0));
1622 __ FCmp();
1623 __ lea(esp, Operand(esp, 2 * kDoubleSize));
1624 break;
1625 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001626 case kX87Float64SilenceNaN: {
1627 Label end, return_qnan;
1628 __ fstp(0);
1629 __ push(ebx);
1630 // Load Half word of HoleNan(SNaN) into ebx
1631 __ mov(ebx, MemOperand(esp, 2 * kInt32Size));
1632 __ cmp(ebx, Immediate(kHoleNanUpper32));
1633 // Check input is HoleNaN(SNaN)?
1634 __ j(equal, &return_qnan, Label::kNear);
1635 // If input isn't HoleNaN(SNaN), just load it and return
1636 __ fld_d(MemOperand(esp, 1 * kInt32Size));
1637 __ jmp(&end);
1638 __ bind(&return_qnan);
1639 // If input is HoleNaN(SNaN), Return QNaN
1640 __ push(Immediate(0xffffffff));
1641 __ push(Immediate(0xfff7ffff));
1642 __ fld_d(MemOperand(esp, 0));
1643 __ lea(esp, Operand(esp, kDoubleSize));
1644 __ bind(&end);
1645 __ pop(ebx);
1646 // Clear stack.
1647 __ lea(esp, Operand(esp, 1 * kDoubleSize));
1648 break;
1649 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001650 case kX87Movsxbl:
1651 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
1652 break;
1653 case kX87Movzxbl:
1654 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
1655 break;
1656 case kX87Movb: {
1657 size_t index = 0;
1658 Operand operand = i.MemoryOperand(&index);
1659 if (HasImmediateInput(instr, index)) {
1660 __ mov_b(operand, i.InputInt8(index));
1661 } else {
1662 __ mov_b(operand, i.InputRegister(index));
1663 }
1664 break;
1665 }
1666 case kX87Movsxwl:
1667 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
1668 break;
1669 case kX87Movzxwl:
1670 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
1671 break;
1672 case kX87Movw: {
1673 size_t index = 0;
1674 Operand operand = i.MemoryOperand(&index);
1675 if (HasImmediateInput(instr, index)) {
1676 __ mov_w(operand, i.InputInt16(index));
1677 } else {
1678 __ mov_w(operand, i.InputRegister(index));
1679 }
1680 break;
1681 }
1682 case kX87Movl:
1683 if (instr->HasOutput()) {
1684 __ mov(i.OutputRegister(), i.MemoryOperand());
1685 } else {
1686 size_t index = 0;
1687 Operand operand = i.MemoryOperand(&index);
1688 if (HasImmediateInput(instr, index)) {
1689 __ mov(operand, i.InputImmediate(index));
1690 } else {
1691 __ mov(operand, i.InputRegister(index));
1692 }
1693 }
1694 break;
1695 case kX87Movsd: {
1696 if (instr->HasOutput()) {
1697 X87Register output = i.OutputDoubleRegister();
1698 USE(output);
1699 DCHECK(output.code() == 0);
1700 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1701 __ VerifyX87StackDepth(1);
1702 }
1703 __ fstp(0);
1704 __ fld_d(i.MemoryOperand());
1705 } else {
1706 size_t index = 0;
1707 Operand operand = i.MemoryOperand(&index);
1708 __ fst_d(operand);
1709 }
1710 break;
1711 }
1712 case kX87Movss: {
1713 if (instr->HasOutput()) {
1714 X87Register output = i.OutputDoubleRegister();
1715 USE(output);
1716 DCHECK(output.code() == 0);
1717 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1718 __ VerifyX87StackDepth(1);
1719 }
1720 __ fstp(0);
1721 __ fld_s(i.MemoryOperand());
1722 } else {
1723 size_t index = 0;
1724 Operand operand = i.MemoryOperand(&index);
1725 __ fst_s(operand);
1726 }
1727 break;
1728 }
1729 case kX87BitcastFI: {
1730 __ mov(i.OutputRegister(), MemOperand(esp, 0));
1731 __ lea(esp, Operand(esp, kFloatSize));
1732 break;
1733 }
1734 case kX87BitcastIF: {
1735 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
1736 __ VerifyX87StackDepth(1);
1737 }
1738 __ fstp(0);
1739 if (instr->InputAt(0)->IsRegister()) {
1740 __ lea(esp, Operand(esp, -kFloatSize));
1741 __ mov(MemOperand(esp, 0), i.InputRegister(0));
1742 __ fld_s(MemOperand(esp, 0));
1743 __ lea(esp, Operand(esp, kFloatSize));
1744 } else {
1745 __ fld_s(i.InputOperand(0));
1746 }
1747 break;
1748 }
1749 case kX87Lea: {
1750 AddressingMode mode = AddressingModeField::decode(instr->opcode());
1751 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
1752 // and addressing mode just happens to work out. The "addl"/"subl" forms
1753 // in these cases are faster based on measurements.
1754 if (mode == kMode_MI) {
1755 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
1756 } else if (i.InputRegister(0).is(i.OutputRegister())) {
1757 if (mode == kMode_MRI) {
1758 int32_t constant_summand = i.InputInt32(1);
1759 if (constant_summand > 0) {
1760 __ add(i.OutputRegister(), Immediate(constant_summand));
1761 } else if (constant_summand < 0) {
1762 __ sub(i.OutputRegister(), Immediate(-constant_summand));
1763 }
1764 } else if (mode == kMode_MR1) {
1765 if (i.InputRegister(1).is(i.OutputRegister())) {
1766 __ shl(i.OutputRegister(), 1);
1767 } else {
1768 __ lea(i.OutputRegister(), i.MemoryOperand());
1769 }
1770 } else if (mode == kMode_M2) {
1771 __ shl(i.OutputRegister(), 1);
1772 } else if (mode == kMode_M4) {
1773 __ shl(i.OutputRegister(), 2);
1774 } else if (mode == kMode_M8) {
1775 __ shl(i.OutputRegister(), 3);
1776 } else {
1777 __ lea(i.OutputRegister(), i.MemoryOperand());
1778 }
1779 } else {
1780 __ lea(i.OutputRegister(), i.MemoryOperand());
1781 }
1782 break;
1783 }
1784 case kX87Push:
Ben Murdochc5610432016-08-08 18:44:38 +01001785 if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001786 auto allocated = AllocatedOperand::cast(*instr->InputAt(0));
1787 if (allocated.representation() == MachineRepresentation::kFloat32) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001788 __ sub(esp, Immediate(kFloatSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001789 __ fst_s(Operand(esp, 0));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001790 frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791 } else {
1792 DCHECK(allocated.representation() == MachineRepresentation::kFloat64);
1793 __ sub(esp, Immediate(kDoubleSize));
1794 __ fst_d(Operand(esp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001795 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001796 }
Ben Murdochc5610432016-08-08 18:44:38 +01001797 } else if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001798 auto allocated = AllocatedOperand::cast(*instr->InputAt(0));
1799 if (allocated.representation() == MachineRepresentation::kFloat32) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001800 __ sub(esp, Immediate(kFloatSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001801 __ fld_s(i.InputOperand(0));
1802 __ fstp_s(MemOperand(esp, 0));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001803 frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001804 } else {
1805 DCHECK(allocated.representation() == MachineRepresentation::kFloat64);
1806 __ sub(esp, Immediate(kDoubleSize));
1807 __ fld_d(i.InputOperand(0));
1808 __ fstp_d(MemOperand(esp, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001809 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001810 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001811 } else if (HasImmediateInput(instr, 0)) {
1812 __ push(i.InputImmediate(0));
1813 frame_access_state()->IncreaseSPDelta(1);
1814 } else {
1815 __ push(i.InputOperand(0));
1816 frame_access_state()->IncreaseSPDelta(1);
1817 }
1818 break;
1819 case kX87Poke: {
1820 int const slot = MiscField::decode(instr->opcode());
1821 if (HasImmediateInput(instr, 0)) {
1822 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
1823 } else {
1824 __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0));
1825 }
1826 break;
1827 }
Ben Murdochc5610432016-08-08 18:44:38 +01001828 case kX87Xchgb: {
1829 size_t index = 0;
1830 Operand operand = i.MemoryOperand(&index);
1831 __ xchg_b(i.InputRegister(index), operand);
1832 break;
1833 }
1834 case kX87Xchgw: {
1835 size_t index = 0;
1836 Operand operand = i.MemoryOperand(&index);
1837 __ xchg_w(i.InputRegister(index), operand);
1838 break;
1839 }
1840 case kX87Xchgl: {
1841 size_t index = 0;
1842 Operand operand = i.MemoryOperand(&index);
1843 __ xchg(i.InputRegister(index), operand);
1844 break;
1845 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001846 case kX87PushFloat32:
1847 __ lea(esp, Operand(esp, -kFloatSize));
Ben Murdochc5610432016-08-08 18:44:38 +01001848 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001849 __ fld_s(i.InputOperand(0));
1850 __ fstp_s(MemOperand(esp, 0));
Ben Murdochc5610432016-08-08 18:44:38 +01001851 } else if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001852 __ fst_s(MemOperand(esp, 0));
1853 } else {
1854 UNREACHABLE();
1855 }
1856 break;
1857 case kX87PushFloat64:
1858 __ lea(esp, Operand(esp, -kDoubleSize));
Ben Murdochc5610432016-08-08 18:44:38 +01001859 if (instr->InputAt(0)->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001860 __ fld_d(i.InputOperand(0));
1861 __ fstp_d(MemOperand(esp, 0));
Ben Murdochc5610432016-08-08 18:44:38 +01001862 } else if (instr->InputAt(0)->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001863 __ fst_d(MemOperand(esp, 0));
1864 } else {
1865 UNREACHABLE();
1866 }
1867 break;
1868 case kCheckedLoadInt8:
1869 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
1870 break;
1871 case kCheckedLoadUint8:
1872 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
1873 break;
1874 case kCheckedLoadInt16:
1875 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
1876 break;
1877 case kCheckedLoadUint16:
1878 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
1879 break;
1880 case kCheckedLoadWord32:
1881 ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
1882 break;
1883 case kCheckedLoadFloat32:
1884 ASSEMBLE_CHECKED_LOAD_FLOAT(fld_s);
1885 break;
1886 case kCheckedLoadFloat64:
1887 ASSEMBLE_CHECKED_LOAD_FLOAT(fld_d);
1888 break;
1889 case kCheckedStoreWord8:
1890 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
1891 break;
1892 case kCheckedStoreWord16:
1893 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
1894 break;
1895 case kCheckedStoreWord32:
1896 ASSEMBLE_CHECKED_STORE_INTEGER(mov);
1897 break;
1898 case kCheckedStoreFloat32:
1899 ASSEMBLE_CHECKED_STORE_FLOAT(fst_s);
1900 break;
1901 case kCheckedStoreFloat64:
1902 ASSEMBLE_CHECKED_STORE_FLOAT(fst_d);
1903 break;
1904 case kX87StackCheck: {
1905 ExternalReference const stack_limit =
1906 ExternalReference::address_of_stack_limit(isolate());
1907 __ cmp(esp, Operand::StaticVariable(stack_limit));
1908 break;
1909 }
1910 case kCheckedLoadWord64:
1911 case kCheckedStoreWord64:
1912 UNREACHABLE(); // currently unsupported checked int64 load/store.
1913 break;
Ben Murdochc5610432016-08-08 18:44:38 +01001914 case kAtomicLoadInt8:
1915 case kAtomicLoadUint8:
1916 case kAtomicLoadInt16:
1917 case kAtomicLoadUint16:
1918 case kAtomicLoadWord32:
1919 case kAtomicStoreWord8:
1920 case kAtomicStoreWord16:
1921 case kAtomicStoreWord32:
1922 UNREACHABLE(); // Won't be generated by instruction selector.
1923 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001924 }
Ben Murdochc5610432016-08-08 18:44:38 +01001925 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926} // NOLINT(readability/fn_size)
1927
1928
1929// Assembles a branch after an instruction.
1930void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1931 X87OperandConverter i(this, instr);
1932 Label::Distance flabel_distance =
1933 branch->fallthru ? Label::kNear : Label::kFar;
Ben Murdochda12d292016-06-02 14:46:10 +01001934
1935 Label done;
1936 Label tlabel_tmp;
1937 Label flabel_tmp;
1938 Label* tlabel = &tlabel_tmp;
1939 Label* flabel = &flabel_tmp;
1940
1941 Label* tlabel_dst = branch->true_label;
1942 Label* flabel_dst = branch->false_label;
1943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944 switch (branch->condition) {
1945 case kUnorderedEqual:
1946 __ j(parity_even, flabel, flabel_distance);
1947 // Fall through.
1948 case kEqual:
1949 __ j(equal, tlabel);
1950 break;
1951 case kUnorderedNotEqual:
1952 __ j(parity_even, tlabel);
1953 // Fall through.
1954 case kNotEqual:
1955 __ j(not_equal, tlabel);
1956 break;
1957 case kSignedLessThan:
1958 __ j(less, tlabel);
1959 break;
1960 case kSignedGreaterThanOrEqual:
1961 __ j(greater_equal, tlabel);
1962 break;
1963 case kSignedLessThanOrEqual:
1964 __ j(less_equal, tlabel);
1965 break;
1966 case kSignedGreaterThan:
1967 __ j(greater, tlabel);
1968 break;
1969 case kUnsignedLessThan:
1970 __ j(below, tlabel);
1971 break;
1972 case kUnsignedGreaterThanOrEqual:
1973 __ j(above_equal, tlabel);
1974 break;
1975 case kUnsignedLessThanOrEqual:
1976 __ j(below_equal, tlabel);
1977 break;
1978 case kUnsignedGreaterThan:
1979 __ j(above, tlabel);
1980 break;
1981 case kOverflow:
1982 __ j(overflow, tlabel);
1983 break;
1984 case kNotOverflow:
1985 __ j(no_overflow, tlabel);
1986 break;
1987 default:
1988 UNREACHABLE();
1989 break;
1990 }
1991 // Add a jump if not falling through to the next block.
1992 if (!branch->fallthru) __ jmp(flabel);
Ben Murdochda12d292016-06-02 14:46:10 +01001993
1994 __ jmp(&done);
1995 __ bind(&tlabel_tmp);
1996 FlagsMode mode = FlagsModeField::decode(instr->opcode());
1997 if (mode == kFlags_deoptimize) {
1998 int double_register_param_count = 0;
1999 int x87_layout = 0;
2000 for (size_t i = 0; i < instr->InputCount(); i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01002001 if (instr->InputAt(i)->IsFPRegister()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002002 double_register_param_count++;
2003 }
2004 }
2005 // Currently we use only one X87 register. If double_register_param_count
2006 // is bigger than 1, it means duplicated double register is added to input
2007 // of this instruction.
2008 if (double_register_param_count > 0) {
2009 x87_layout = (0 << 3) | 1;
2010 }
2011 // The layout of x87 register stack is loaded on the top of FPU register
2012 // stack for deoptimization.
2013 __ push(Immediate(x87_layout));
2014 __ fild_s(MemOperand(esp, 0));
2015 __ lea(esp, Operand(esp, kPointerSize));
2016 }
2017 __ jmp(tlabel_dst);
2018 __ bind(&flabel_tmp);
2019 __ jmp(flabel_dst);
2020 __ bind(&done);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002021}
2022
2023
2024void CodeGenerator::AssembleArchJump(RpoNumber target) {
2025 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
2026}
2027
2028
2029// Assembles boolean materializations after an instruction.
2030void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2031 FlagsCondition condition) {
2032 X87OperandConverter i(this, instr);
2033 Label done;
2034
2035 // Materialize a full 32-bit 1 or 0 value. The result register is always the
2036 // last output of the instruction.
2037 Label check;
2038 DCHECK_NE(0u, instr->OutputCount());
2039 Register reg = i.OutputRegister(instr->OutputCount() - 1);
2040 Condition cc = no_condition;
2041 switch (condition) {
2042 case kUnorderedEqual:
2043 __ j(parity_odd, &check, Label::kNear);
2044 __ Move(reg, Immediate(0));
2045 __ jmp(&done, Label::kNear);
2046 // Fall through.
2047 case kEqual:
2048 cc = equal;
2049 break;
2050 case kUnorderedNotEqual:
2051 __ j(parity_odd, &check, Label::kNear);
2052 __ mov(reg, Immediate(1));
2053 __ jmp(&done, Label::kNear);
2054 // Fall through.
2055 case kNotEqual:
2056 cc = not_equal;
2057 break;
2058 case kSignedLessThan:
2059 cc = less;
2060 break;
2061 case kSignedGreaterThanOrEqual:
2062 cc = greater_equal;
2063 break;
2064 case kSignedLessThanOrEqual:
2065 cc = less_equal;
2066 break;
2067 case kSignedGreaterThan:
2068 cc = greater;
2069 break;
2070 case kUnsignedLessThan:
2071 cc = below;
2072 break;
2073 case kUnsignedGreaterThanOrEqual:
2074 cc = above_equal;
2075 break;
2076 case kUnsignedLessThanOrEqual:
2077 cc = below_equal;
2078 break;
2079 case kUnsignedGreaterThan:
2080 cc = above;
2081 break;
2082 case kOverflow:
2083 cc = overflow;
2084 break;
2085 case kNotOverflow:
2086 cc = no_overflow;
2087 break;
2088 default:
2089 UNREACHABLE();
2090 break;
2091 }
2092 __ bind(&check);
2093 if (reg.is_byte_register()) {
2094 // setcc for byte registers (al, bl, cl, dl).
2095 __ setcc(cc, reg);
2096 __ movzx_b(reg, reg);
2097 } else {
2098 // Emit a branch to set a register to either 1 or 0.
2099 Label set;
2100 __ j(cc, &set, Label::kNear);
2101 __ Move(reg, Immediate(0));
2102 __ jmp(&done, Label::kNear);
2103 __ bind(&set);
2104 __ mov(reg, Immediate(1));
2105 }
2106 __ bind(&done);
2107}
2108
2109
2110void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
2111 X87OperandConverter i(this, instr);
2112 Register input = i.InputRegister(0);
2113 for (size_t index = 2; index < instr->InputCount(); index += 2) {
2114 __ cmp(input, Immediate(i.InputInt32(index + 0)));
2115 __ j(equal, GetLabel(i.InputRpo(index + 1)));
2116 }
2117 AssembleArchJump(i.InputRpo(1));
2118}
2119
2120
2121void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2122 X87OperandConverter i(this, instr);
2123 Register input = i.InputRegister(0);
2124 size_t const case_count = instr->InputCount() - 2;
2125 Label** cases = zone()->NewArray<Label*>(case_count);
2126 for (size_t index = 0; index < case_count; ++index) {
2127 cases[index] = GetLabel(i.InputRpo(index + 2));
2128 }
2129 Label* const table = AddJumpTable(cases, case_count);
2130 __ cmp(input, Immediate(case_count));
2131 __ j(above_equal, GetLabel(i.InputRpo(1)));
2132 __ jmp(Operand::JumpTable(input, times_4, table));
2133}
2134
Ben Murdochc5610432016-08-08 18:44:38 +01002135CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002136 int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
2137 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
2138 isolate(), deoptimization_id, bailout_type);
Ben Murdochc5610432016-08-08 18:44:38 +01002139 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002140 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
Ben Murdochc5610432016-08-08 18:44:38 +01002141 return kSuccess;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002142}
2143
2144
2145// The calling convention for JSFunctions on X87 passes arguments on the
2146// stack and the JSFunction and context in EDI and ESI, respectively, thus
2147// the steps of the call look as follows:
2148
2149// --{ before the call instruction }--------------------------------------------
2150// | caller frame |
2151// ^ esp ^ ebp
2152
2153// --{ push arguments and setup ESI, EDI }--------------------------------------
2154// | args + receiver | caller frame |
2155// ^ esp ^ ebp
2156// [edi = JSFunction, esi = context]
2157
2158// --{ call [edi + kCodeEntryOffset] }------------------------------------------
2159// | RET | args + receiver | caller frame |
2160// ^ esp ^ ebp
2161
2162// =={ prologue of called function }============================================
2163// --{ push ebp }---------------------------------------------------------------
2164// | FP | RET | args + receiver | caller frame |
2165// ^ esp ^ ebp
2166
2167// --{ mov ebp, esp }-----------------------------------------------------------
2168// | FP | RET | args + receiver | caller frame |
2169// ^ ebp,esp
2170
2171// --{ push esi }---------------------------------------------------------------
2172// | CTX | FP | RET | args + receiver | caller frame |
2173// ^esp ^ ebp
2174
2175// --{ push edi }---------------------------------------------------------------
2176// | FNC | CTX | FP | RET | args + receiver | caller frame |
2177// ^esp ^ ebp
2178
2179// --{ subi esp, #N }-----------------------------------------------------------
2180// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
2181// ^esp ^ ebp
2182
2183// =={ body of called function }================================================
2184
2185// =={ epilogue of called function }============================================
2186// --{ mov esp, ebp }-----------------------------------------------------------
2187// | FP | RET | args + receiver | caller frame |
2188// ^ esp,ebp
2189
2190// --{ pop ebp }-----------------------------------------------------------
2191// | | RET | args + receiver | caller frame |
2192// ^ esp ^ ebp
2193
2194// --{ ret #A+1 }-----------------------------------------------------------
2195// | | caller frame |
2196// ^ esp ^ ebp
2197
2198
2199// Runtime function calls are accomplished by doing a stub call to the
2200// CEntryStub (a real code object). On X87 passes arguments on the
2201// stack, the number of arguments in EAX, the address of the runtime function
2202// in EBX, and the context in ESI.
2203
2204// --{ before the call instruction }--------------------------------------------
2205// | caller frame |
2206// ^ esp ^ ebp
2207
2208// --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
2209// | args + receiver | caller frame |
2210// ^ esp ^ ebp
2211// [eax = #args, ebx = runtime function, esi = context]
2212
2213// --{ call #CEntryStub }-------------------------------------------------------
2214// | RET | args + receiver | caller frame |
2215// ^ esp ^ ebp
2216
2217// =={ body of runtime function }===============================================
2218
2219// --{ runtime returns }--------------------------------------------------------
2220// | caller frame |
2221// ^ esp ^ ebp
2222
2223// Other custom linkages (e.g. for calling directly into and out of C++) may
2224// need to save callee-saved registers on the stack, which is done in the
2225// function prologue of generated code.
2226
2227// --{ before the call instruction }--------------------------------------------
2228// | caller frame |
2229// ^ esp ^ ebp
2230
2231// --{ set up arguments in registers on stack }---------------------------------
2232// | args | caller frame |
2233// ^ esp ^ ebp
2234// [r0 = arg0, r1 = arg1, ...]
2235
2236// --{ call code }--------------------------------------------------------------
2237// | RET | args | caller frame |
2238// ^ esp ^ ebp
2239
2240// =={ prologue of called function }============================================
2241// --{ push ebp }---------------------------------------------------------------
2242// | FP | RET | args | caller frame |
2243// ^ esp ^ ebp
2244
2245// --{ mov ebp, esp }-----------------------------------------------------------
2246// | FP | RET | args | caller frame |
2247// ^ ebp,esp
2248
2249// --{ save registers }---------------------------------------------------------
2250// | regs | FP | RET | args | caller frame |
2251// ^ esp ^ ebp
2252
2253// --{ subi esp, #N }-----------------------------------------------------------
2254// | callee frame | regs | FP | RET | args | caller frame |
2255// ^esp ^ ebp
2256
2257// =={ body of called function }================================================
2258
2259// =={ epilogue of called function }============================================
2260// --{ restore registers }------------------------------------------------------
2261// | regs | FP | RET | args | caller frame |
2262// ^ esp ^ ebp
2263
2264// --{ mov esp, ebp }-----------------------------------------------------------
2265// | FP | RET | args | caller frame |
2266// ^ esp,ebp
2267
2268// --{ pop ebp }----------------------------------------------------------------
2269// | RET | args | caller frame |
2270// ^ esp ^ ebp
2271
Ben Murdochc5610432016-08-08 18:44:38 +01002272void CodeGenerator::FinishFrame(Frame* frame) {
2273 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2274 const RegList saves = descriptor->CalleeSavedRegisters();
2275 if (saves != 0) { // Save callee-saved registers.
2276 DCHECK(!info()->is_osr());
2277 int pushed = 0;
2278 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
2279 if (!((1 << i) & saves)) continue;
2280 ++pushed;
2281 }
2282 frame->AllocateSavedCalleeRegisterSlots(pushed);
2283 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002284
Ben Murdochc5610432016-08-08 18:44:38 +01002285 // Initailize FPU state.
2286 __ fninit();
2287 __ fld1();
2288}
2289
2290void CodeGenerator::AssembleConstructFrame() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002291 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
Ben Murdochda12d292016-06-02 14:46:10 +01002292 if (frame_access_state()->has_frame()) {
2293 if (descriptor->IsCFunctionCall()) {
2294 __ push(ebp);
2295 __ mov(ebp, esp);
2296 } else if (descriptor->IsJSFunctionCall()) {
2297 __ Prologue(this->info()->GeneratePreagedPrologue());
2298 } else {
2299 __ StubPrologue(info()->GetOutputStackFrameType());
2300 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002301 }
Ben Murdochc5610432016-08-08 18:44:38 +01002302
2303 int shrink_slots = frame()->GetSpillSlotCount();
2304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002305 if (info()->is_osr()) {
2306 // TurboFan OSR-compiled functions cannot be entered directly.
2307 __ Abort(kShouldNotDirectlyEnterOsrFunction);
2308
2309 // Unoptimized code jumps directly to this entrypoint while the unoptimized
2310 // frame is still on the stack. Optimized code uses OSR values directly from
2311 // the unoptimized frame. Thus, all that needs to be done is to allocate the
2312 // remaining stack slots.
2313 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2314 osr_pc_offset_ = __ pc_offset();
Ben Murdochc5610432016-08-08 18:44:38 +01002315 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
Ben Murdochda12d292016-06-02 14:46:10 +01002316
2317 // Initailize FPU state.
2318 __ fninit();
2319 __ fld1();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002320 }
2321
2322 const RegList saves = descriptor->CalleeSavedRegisters();
Ben Murdochc5610432016-08-08 18:44:38 +01002323 if (shrink_slots > 0) {
2324 __ sub(esp, Immediate(shrink_slots * kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002325 }
2326
2327 if (saves != 0) { // Save callee-saved registers.
2328 DCHECK(!info()->is_osr());
2329 int pushed = 0;
2330 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
2331 if (!((1 << i) & saves)) continue;
2332 __ push(Register::from_code(i));
2333 ++pushed;
2334 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002335 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002336}
2337
2338
2339void CodeGenerator::AssembleReturn() {
2340 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2341
2342 // Clear the FPU stack only if there is no return value in the stack.
2343 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
2344 __ VerifyX87StackDepth(1);
2345 }
2346 bool clear_stack = true;
2347 for (int i = 0; i < descriptor->ReturnCount(); i++) {
2348 MachineRepresentation rep = descriptor->GetReturnType(i).representation();
2349 LinkageLocation loc = descriptor->GetReturnLocation(i);
2350 if (IsFloatingPoint(rep) && loc == LinkageLocation::ForRegister(0)) {
2351 clear_stack = false;
2352 break;
2353 }
2354 }
2355 if (clear_stack) __ fstp(0);
2356
2357 int pop_count = static_cast<int>(descriptor->StackParameterCount());
2358 const RegList saves = descriptor->CalleeSavedRegisters();
2359 // Restore registers.
2360 if (saves != 0) {
2361 for (int i = 0; i < Register::kNumRegisters; i++) {
2362 if (!((1 << i) & saves)) continue;
2363 __ pop(Register::from_code(i));
2364 }
2365 }
2366
2367 if (descriptor->IsCFunctionCall()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002368 AssembleDeconstructFrame();
2369 } else if (frame_access_state()->has_frame()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002370 // Canonicalize JSFunction return sites for now.
2371 if (return_label_.is_bound()) {
2372 __ jmp(&return_label_);
2373 return;
2374 } else {
2375 __ bind(&return_label_);
Ben Murdochda12d292016-06-02 14:46:10 +01002376 AssembleDeconstructFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002377 }
2378 }
2379 if (pop_count == 0) {
2380 __ ret(0);
2381 } else {
2382 __ Ret(pop_count * kPointerSize, ebx);
2383 }
2384}
2385
2386
2387void CodeGenerator::AssembleMove(InstructionOperand* source,
2388 InstructionOperand* destination) {
2389 X87OperandConverter g(this, nullptr);
2390 // Dispatch on the source and destination operand kinds. Not all
2391 // combinations are possible.
2392 if (source->IsRegister()) {
2393 DCHECK(destination->IsRegister() || destination->IsStackSlot());
2394 Register src = g.ToRegister(source);
2395 Operand dst = g.ToOperand(destination);
2396 __ mov(dst, src);
2397 } else if (source->IsStackSlot()) {
2398 DCHECK(destination->IsRegister() || destination->IsStackSlot());
2399 Operand src = g.ToOperand(source);
2400 if (destination->IsRegister()) {
2401 Register dst = g.ToRegister(destination);
2402 __ mov(dst, src);
2403 } else {
2404 Operand dst = g.ToOperand(destination);
2405 __ push(src);
2406 __ pop(dst);
2407 }
2408 } else if (source->IsConstant()) {
2409 Constant src_constant = g.ToConstant(source);
2410 if (src_constant.type() == Constant::kHeapObject) {
2411 Handle<HeapObject> src = src_constant.ToHeapObject();
Ben Murdochda12d292016-06-02 14:46:10 +01002412 int slot;
2413 if (IsMaterializableFromFrame(src, &slot)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002414 if (destination->IsRegister()) {
2415 Register dst = g.ToRegister(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01002416 __ mov(dst, g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002417 } else {
2418 DCHECK(destination->IsStackSlot());
2419 Operand dst = g.ToOperand(destination);
Ben Murdochda12d292016-06-02 14:46:10 +01002420 __ push(g.SlotToOperand(slot));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002421 __ pop(dst);
2422 }
2423 } else if (destination->IsRegister()) {
2424 Register dst = g.ToRegister(destination);
2425 __ LoadHeapObject(dst, src);
2426 } else {
2427 DCHECK(destination->IsStackSlot());
2428 Operand dst = g.ToOperand(destination);
2429 AllowDeferredHandleDereference embedding_raw_address;
2430 if (isolate()->heap()->InNewSpace(*src)) {
2431 __ PushHeapObject(src);
2432 __ pop(dst);
2433 } else {
2434 __ mov(dst, src);
2435 }
2436 }
2437 } else if (destination->IsRegister()) {
2438 Register dst = g.ToRegister(destination);
2439 __ Move(dst, g.ToImmediate(source));
2440 } else if (destination->IsStackSlot()) {
2441 Operand dst = g.ToOperand(destination);
2442 __ Move(dst, g.ToImmediate(source));
2443 } else if (src_constant.type() == Constant::kFloat32) {
2444 // TODO(turbofan): Can we do better here?
2445 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
Ben Murdochc5610432016-08-08 18:44:38 +01002446 if (destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002447 __ sub(esp, Immediate(kInt32Size));
2448 __ mov(MemOperand(esp, 0), Immediate(src));
2449 // always only push one value into the x87 stack.
2450 __ fstp(0);
2451 __ fld_s(MemOperand(esp, 0));
2452 __ add(esp, Immediate(kInt32Size));
2453 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002454 DCHECK(destination->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002455 Operand dst = g.ToOperand(destination);
2456 __ Move(dst, Immediate(src));
2457 }
2458 } else {
2459 DCHECK_EQ(Constant::kFloat64, src_constant.type());
2460 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
2461 uint32_t lower = static_cast<uint32_t>(src);
2462 uint32_t upper = static_cast<uint32_t>(src >> 32);
Ben Murdochc5610432016-08-08 18:44:38 +01002463 if (destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002464 __ sub(esp, Immediate(kDoubleSize));
2465 __ mov(MemOperand(esp, 0), Immediate(lower));
2466 __ mov(MemOperand(esp, kInt32Size), Immediate(upper));
2467 // always only push one value into the x87 stack.
2468 __ fstp(0);
2469 __ fld_d(MemOperand(esp, 0));
2470 __ add(esp, Immediate(kDoubleSize));
2471 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002472 DCHECK(destination->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473 Operand dst0 = g.ToOperand(destination);
2474 Operand dst1 = g.HighOperand(destination);
2475 __ Move(dst0, Immediate(lower));
2476 __ Move(dst1, Immediate(upper));
2477 }
2478 }
Ben Murdochc5610432016-08-08 18:44:38 +01002479 } else if (source->IsFPRegister()) {
2480 DCHECK(destination->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002481 Operand dst = g.ToOperand(destination);
2482 auto allocated = AllocatedOperand::cast(*source);
2483 switch (allocated.representation()) {
2484 case MachineRepresentation::kFloat32:
2485 __ fst_s(dst);
2486 break;
2487 case MachineRepresentation::kFloat64:
2488 __ fst_d(dst);
2489 break;
2490 default:
2491 UNREACHABLE();
2492 }
Ben Murdochc5610432016-08-08 18:44:38 +01002493 } else if (source->IsFPStackSlot()) {
2494 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002495 Operand src = g.ToOperand(source);
2496 auto allocated = AllocatedOperand::cast(*source);
Ben Murdochc5610432016-08-08 18:44:38 +01002497 if (destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 // always only push one value into the x87 stack.
2499 __ fstp(0);
2500 switch (allocated.representation()) {
2501 case MachineRepresentation::kFloat32:
2502 __ fld_s(src);
2503 break;
2504 case MachineRepresentation::kFloat64:
2505 __ fld_d(src);
2506 break;
2507 default:
2508 UNREACHABLE();
2509 }
2510 } else {
2511 Operand dst = g.ToOperand(destination);
2512 switch (allocated.representation()) {
2513 case MachineRepresentation::kFloat32:
2514 __ fld_s(src);
2515 __ fstp_s(dst);
2516 break;
2517 case MachineRepresentation::kFloat64:
2518 __ fld_d(src);
2519 __ fstp_d(dst);
2520 break;
2521 default:
2522 UNREACHABLE();
2523 }
2524 }
2525 } else {
2526 UNREACHABLE();
2527 }
2528}
2529
2530
2531void CodeGenerator::AssembleSwap(InstructionOperand* source,
2532 InstructionOperand* destination) {
2533 X87OperandConverter g(this, nullptr);
2534 // Dispatch on the source and destination operand kinds. Not all
2535 // combinations are possible.
2536 if (source->IsRegister() && destination->IsRegister()) {
2537 // Register-register.
2538 Register src = g.ToRegister(source);
2539 Register dst = g.ToRegister(destination);
2540 __ xchg(dst, src);
2541 } else if (source->IsRegister() && destination->IsStackSlot()) {
2542 // Register-memory.
2543 __ xchg(g.ToRegister(source), g.ToOperand(destination));
2544 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
2545 // Memory-memory.
2546 Operand dst1 = g.ToOperand(destination);
2547 __ push(dst1);
2548 frame_access_state()->IncreaseSPDelta(1);
2549 Operand src1 = g.ToOperand(source);
2550 __ push(src1);
2551 Operand dst2 = g.ToOperand(destination);
2552 __ pop(dst2);
2553 frame_access_state()->IncreaseSPDelta(-1);
2554 Operand src2 = g.ToOperand(source);
2555 __ pop(src2);
Ben Murdochc5610432016-08-08 18:44:38 +01002556 } else if (source->IsFPRegister() && destination->IsFPRegister()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002557 UNREACHABLE();
Ben Murdochc5610432016-08-08 18:44:38 +01002558 } else if (source->IsFPRegister() && destination->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002559 auto allocated = AllocatedOperand::cast(*source);
2560 switch (allocated.representation()) {
2561 case MachineRepresentation::kFloat32:
2562 __ fld_s(g.ToOperand(destination));
2563 __ fxch();
2564 __ fstp_s(g.ToOperand(destination));
2565 break;
2566 case MachineRepresentation::kFloat64:
2567 __ fld_d(g.ToOperand(destination));
2568 __ fxch();
2569 __ fstp_d(g.ToOperand(destination));
2570 break;
2571 default:
2572 UNREACHABLE();
2573 }
Ben Murdochc5610432016-08-08 18:44:38 +01002574 } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002575 auto allocated = AllocatedOperand::cast(*source);
2576 switch (allocated.representation()) {
2577 case MachineRepresentation::kFloat32:
2578 __ fld_s(g.ToOperand(source));
2579 __ fld_s(g.ToOperand(destination));
2580 __ fstp_s(g.ToOperand(source));
2581 __ fstp_s(g.ToOperand(destination));
2582 break;
2583 case MachineRepresentation::kFloat64:
2584 __ fld_d(g.ToOperand(source));
2585 __ fld_d(g.ToOperand(destination));
2586 __ fstp_d(g.ToOperand(source));
2587 __ fstp_d(g.ToOperand(destination));
2588 break;
2589 default:
2590 UNREACHABLE();
2591 }
2592 } else {
2593 // No other combinations are possible.
2594 UNREACHABLE();
2595 }
2596}
2597
2598
2599void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2600 for (size_t index = 0; index < target_count; ++index) {
2601 __ dd(targets[index]);
2602 }
2603}
2604
2605
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002606void CodeGenerator::EnsureSpaceForLazyDeopt() {
2607 if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2608 return;
2609 }
2610
2611 int space_needed = Deoptimizer::patch_size();
2612 // Ensure that we have enough space after the previous lazy-bailout
2613 // instruction for patching the code here.
2614 int current_pc = masm()->pc_offset();
2615 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2616 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2617 __ Nop(padding_size);
2618 }
2619}
2620
2621#undef __
2622
2623} // namespace compiler
2624} // namespace internal
2625} // namespace v8