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