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