code-generator-ia32.cc revision 537ba893e2530051ec7f296e769fdd37bb4ae4a0
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/ast/scopes.h" 8#include "src/compiler/code-generator-impl.h" 9#include "src/compiler/gap-resolver.h" 10#include "src/compiler/node-matchers.h" 11#include "src/compiler/osr.h" 12#include "src/frames.h" 13#include "src/ia32/assembler-ia32.h" 14#include "src/ia32/frames-ia32.h" 15#include "src/ia32/macro-assembler-ia32.h" 16 17namespace v8 { 18namespace internal { 19namespace compiler { 20 21#define __ masm()-> 22 23 24#define kScratchDoubleReg xmm0 25 26 27// Adds IA-32 specific methods for decoding operands. 28class IA32OperandConverter : public InstructionOperandConverter { 29 public: 30 IA32OperandConverter(CodeGenerator* gen, Instruction* instr) 31 : InstructionOperandConverter(gen, instr) {} 32 33 Operand InputOperand(size_t index, int extra = 0) { 34 return ToOperand(instr_->InputAt(index), extra); 35 } 36 37 Immediate InputImmediate(size_t index) { 38 return ToImmediate(instr_->InputAt(index)); 39 } 40 41 Operand OutputOperand() { return ToOperand(instr_->Output()); } 42 43 Operand ToOperand(InstructionOperand* op, int extra = 0) { 44 if (op->IsRegister()) { 45 DCHECK(extra == 0); 46 return Operand(ToRegister(op)); 47 } else if (op->IsFPRegister()) { 48 DCHECK(extra == 0); 49 return Operand(ToDoubleRegister(op)); 50 } 51 DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); 52 return SlotToOperand(AllocatedOperand::cast(op)->index(), extra); 53 } 54 55 Operand SlotToOperand(int slot, int extra = 0) { 56 FrameOffset offset = frame_access_state()->GetFrameOffset(slot); 57 return Operand(offset.from_stack_pointer() ? esp : ebp, 58 offset.offset() + extra); 59 } 60 61 Operand HighOperand(InstructionOperand* op) { 62 DCHECK(op->IsFPStackSlot()); 63 return ToOperand(op, kPointerSize); 64 } 65 66 Immediate ToImmediate(InstructionOperand* operand) { 67 Constant constant = ToConstant(operand); 68 if (constant.type() == Constant::kInt32 && 69 (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE || 70 constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) { 71 return Immediate(reinterpret_cast<Address>(constant.ToInt32()), 72 constant.rmode()); 73 } 74 switch (constant.type()) { 75 case Constant::kInt32: 76 return Immediate(constant.ToInt32()); 77 case Constant::kFloat32: 78 return Immediate( 79 isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); 80 case Constant::kFloat64: 81 return Immediate( 82 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED)); 83 case Constant::kExternalReference: 84 return Immediate(constant.ToExternalReference()); 85 case Constant::kHeapObject: 86 return Immediate(constant.ToHeapObject()); 87 case Constant::kInt64: 88 break; 89 case Constant::kRpoNumber: 90 return Immediate::CodeRelativeOffset(ToLabel(operand)); 91 } 92 UNREACHABLE(); 93 return Immediate(-1); 94 } 95 96 static size_t NextOffset(size_t* offset) { 97 size_t i = *offset; 98 (*offset)++; 99 return i; 100 } 101 102 static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) { 103 STATIC_ASSERT(0 == static_cast<int>(times_1)); 104 STATIC_ASSERT(1 == static_cast<int>(times_2)); 105 STATIC_ASSERT(2 == static_cast<int>(times_4)); 106 STATIC_ASSERT(3 == static_cast<int>(times_8)); 107 int scale = static_cast<int>(mode - one); 108 DCHECK(scale >= 0 && scale < 4); 109 return static_cast<ScaleFactor>(scale); 110 } 111 112 Operand MemoryOperand(size_t* offset) { 113 AddressingMode mode = AddressingModeField::decode(instr_->opcode()); 114 switch (mode) { 115 case kMode_MR: { 116 Register base = InputRegister(NextOffset(offset)); 117 int32_t disp = 0; 118 return Operand(base, disp); 119 } 120 case kMode_MRI: { 121 Register base = InputRegister(NextOffset(offset)); 122 int32_t disp = InputInt32(NextOffset(offset)); 123 return Operand(base, disp); 124 } 125 case kMode_MR1: 126 case kMode_MR2: 127 case kMode_MR4: 128 case kMode_MR8: { 129 Register base = InputRegister(NextOffset(offset)); 130 Register index = InputRegister(NextOffset(offset)); 131 ScaleFactor scale = ScaleFor(kMode_MR1, mode); 132 int32_t disp = 0; 133 return Operand(base, index, scale, disp); 134 } 135 case kMode_MR1I: 136 case kMode_MR2I: 137 case kMode_MR4I: 138 case kMode_MR8I: { 139 Register base = InputRegister(NextOffset(offset)); 140 Register index = InputRegister(NextOffset(offset)); 141 ScaleFactor scale = ScaleFor(kMode_MR1I, mode); 142 int32_t disp = InputInt32(NextOffset(offset)); 143 return Operand(base, index, scale, disp); 144 } 145 case kMode_M1: 146 case kMode_M2: 147 case kMode_M4: 148 case kMode_M8: { 149 Register index = InputRegister(NextOffset(offset)); 150 ScaleFactor scale = ScaleFor(kMode_M1, mode); 151 int32_t disp = 0; 152 return Operand(index, scale, disp); 153 } 154 case kMode_M1I: 155 case kMode_M2I: 156 case kMode_M4I: 157 case kMode_M8I: { 158 Register index = InputRegister(NextOffset(offset)); 159 ScaleFactor scale = ScaleFor(kMode_M1I, mode); 160 int32_t disp = InputInt32(NextOffset(offset)); 161 return Operand(index, scale, disp); 162 } 163 case kMode_MI: { 164 int32_t disp = InputInt32(NextOffset(offset)); 165 return Operand(Immediate(disp)); 166 } 167 case kMode_None: 168 UNREACHABLE(); 169 return Operand(no_reg, 0); 170 } 171 UNREACHABLE(); 172 return Operand(no_reg, 0); 173 } 174 175 Operand MemoryOperand(size_t first_input = 0) { 176 return MemoryOperand(&first_input); 177 } 178}; 179 180 181namespace { 182 183bool HasImmediateInput(Instruction* instr, size_t index) { 184 return instr->InputAt(index)->IsImmediate(); 185} 186 187 188class OutOfLineLoadInteger final : public OutOfLineCode { 189 public: 190 OutOfLineLoadInteger(CodeGenerator* gen, Register result) 191 : OutOfLineCode(gen), result_(result) {} 192 193 void Generate() final { __ xor_(result_, result_); } 194 195 private: 196 Register const result_; 197}; 198 199 200class OutOfLineLoadFloat final : public OutOfLineCode { 201 public: 202 OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result) 203 : OutOfLineCode(gen), result_(result) {} 204 205 void Generate() final { __ pcmpeqd(result_, result_); } 206 207 private: 208 XMMRegister const result_; 209}; 210 211 212class OutOfLineTruncateDoubleToI final : public OutOfLineCode { 213 public: 214 OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result, 215 XMMRegister input) 216 : OutOfLineCode(gen), result_(result), input_(input) {} 217 218 void Generate() final { 219 __ sub(esp, Immediate(kDoubleSize)); 220 __ movsd(MemOperand(esp, 0), input_); 221 __ SlowTruncateToI(result_, esp, 0); 222 __ add(esp, Immediate(kDoubleSize)); 223 } 224 225 private: 226 Register const result_; 227 XMMRegister const input_; 228}; 229 230 231class OutOfLineRecordWrite final : public OutOfLineCode { 232 public: 233 OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand, 234 Register value, Register scratch0, Register scratch1, 235 RecordWriteMode mode) 236 : OutOfLineCode(gen), 237 object_(object), 238 operand_(operand), 239 value_(value), 240 scratch0_(scratch0), 241 scratch1_(scratch1), 242 mode_(mode) {} 243 244 void Generate() final { 245 if (mode_ > RecordWriteMode::kValueIsPointer) { 246 __ JumpIfSmi(value_, exit()); 247 } 248 __ CheckPageFlag(value_, scratch0_, 249 MemoryChunk::kPointersToHereAreInterestingMask, zero, 250 exit()); 251 RememberedSetAction const remembered_set_action = 252 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET 253 : OMIT_REMEMBERED_SET; 254 SaveFPRegsMode const save_fp_mode = 255 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; 256 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, 257 remembered_set_action, save_fp_mode); 258 __ lea(scratch1_, operand_); 259 __ CallStub(&stub); 260 } 261 262 private: 263 Register const object_; 264 Operand const operand_; 265 Register const value_; 266 Register const scratch0_; 267 Register const scratch1_; 268 RecordWriteMode const mode_; 269}; 270 271} // namespace 272 273 274#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr) \ 275 do { \ 276 auto result = i.OutputDoubleRegister(); \ 277 auto offset = i.InputRegister(0); \ 278 if (instr->InputAt(1)->IsRegister()) { \ 279 __ cmp(offset, i.InputRegister(1)); \ 280 } else { \ 281 __ cmp(offset, i.InputImmediate(1)); \ 282 } \ 283 OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \ 284 __ j(above_equal, ool->entry()); \ 285 __ asm_instr(result, i.MemoryOperand(2)); \ 286 __ bind(ool->exit()); \ 287 } while (false) 288 289 290#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ 291 do { \ 292 auto result = i.OutputRegister(); \ 293 auto offset = i.InputRegister(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()) OutOfLineLoadInteger(this, result); \ 300 __ j(above_equal, ool->entry()); \ 301 __ asm_instr(result, i.MemoryOperand(2)); \ 302 __ bind(ool->exit()); \ 303 } while (false) 304 305 306#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ 307 do { \ 308 auto offset = i.InputRegister(0); \ 309 if (instr->InputAt(1)->IsRegister()) { \ 310 __ cmp(offset, i.InputRegister(1)); \ 311 } else { \ 312 __ cmp(offset, i.InputImmediate(1)); \ 313 } \ 314 Label done; \ 315 __ j(above_equal, &done, Label::kNear); \ 316 __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \ 317 __ bind(&done); \ 318 } while (false) 319 320 321#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ 322 do { \ 323 auto offset = i.InputRegister(0); \ 324 if (instr->InputAt(1)->IsRegister()) { \ 325 __ cmp(offset, i.InputRegister(1)); \ 326 } else { \ 327 __ cmp(offset, i.InputImmediate(1)); \ 328 } \ 329 Label done; \ 330 __ j(above_equal, &done, Label::kNear); \ 331 if (instr->InputAt(2)->IsRegister()) { \ 332 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \ 333 } else { \ 334 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \ 335 } \ 336 __ bind(&done); \ 337 } while (false) 338 339#define ASSEMBLE_COMPARE(asm_instr) \ 340 do { \ 341 if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \ 342 size_t index = 0; \ 343 Operand left = i.MemoryOperand(&index); \ 344 if (HasImmediateInput(instr, index)) { \ 345 __ asm_instr(left, i.InputImmediate(index)); \ 346 } else { \ 347 __ asm_instr(left, i.InputRegister(index)); \ 348 } \ 349 } else { \ 350 if (HasImmediateInput(instr, 1)) { \ 351 if (instr->InputAt(0)->IsRegister()) { \ 352 __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \ 353 } else { \ 354 __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \ 355 } \ 356 } else { \ 357 if (instr->InputAt(1)->IsRegister()) { \ 358 __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \ 359 } else { \ 360 __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \ 361 } \ 362 } \ 363 } \ 364 } while (0) 365 366void CodeGenerator::AssembleDeconstructFrame() { 367 __ mov(esp, ebp); 368 __ pop(ebp); 369} 370 371void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { 372 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); 373 if (sp_slot_delta > 0) { 374 __ add(esp, Immediate(sp_slot_delta * kPointerSize)); 375 } 376 frame_access_state()->SetFrameAccessToDefault(); 377} 378 379 380void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { 381 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); 382 if (sp_slot_delta < 0) { 383 __ sub(esp, Immediate(-sp_slot_delta * kPointerSize)); 384 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); 385 } 386 if (frame_access_state()->has_frame()) { 387 __ mov(ebp, MemOperand(ebp, 0)); 388 } 389 frame_access_state()->SetFrameAccessToSP(); 390} 391 392void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, 393 Register, Register, 394 Register) { 395 // There are not enough temp registers left on ia32 for a call instruction 396 // so we pick some scratch registers and save/restore them manually here. 397 int scratch_count = 3; 398 Register scratch1 = ebx; 399 Register scratch2 = ecx; 400 Register scratch3 = edx; 401 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); 402 Label done; 403 404 // Check if current frame is an arguments adaptor frame. 405 __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset), 406 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 407 __ j(not_equal, &done, Label::kNear); 408 409 __ push(scratch1); 410 __ push(scratch2); 411 __ push(scratch3); 412 413 // Load arguments count from current arguments adaptor frame (note, it 414 // does not include receiver). 415 Register caller_args_count_reg = scratch1; 416 __ mov(caller_args_count_reg, 417 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 418 __ SmiUntag(caller_args_count_reg); 419 420 ParameterCount callee_args_count(args_reg); 421 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, 422 scratch3, ReturnAddressState::kOnStack, scratch_count); 423 __ pop(scratch3); 424 __ pop(scratch2); 425 __ pop(scratch1); 426 427 __ bind(&done); 428} 429 430// Assembles an instruction after register allocation, producing machine code. 431CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( 432 Instruction* instr) { 433 IA32OperandConverter i(this, instr); 434 InstructionCode opcode = instr->opcode(); 435 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); 436 switch (arch_opcode) { 437 case kArchCallCodeObject: { 438 EnsureSpaceForLazyDeopt(); 439 if (HasImmediateInput(instr, 0)) { 440 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); 441 __ call(code, RelocInfo::CODE_TARGET); 442 } else { 443 Register reg = i.InputRegister(0); 444 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag)); 445 __ call(reg); 446 } 447 RecordCallPosition(instr); 448 frame_access_state()->ClearSPDelta(); 449 break; 450 } 451 case kArchTailCallCodeObjectFromJSFunction: 452 case kArchTailCallCodeObject: { 453 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 454 AssembleDeconstructActivationRecord(stack_param_delta); 455 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { 456 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 457 no_reg, no_reg, no_reg); 458 } 459 if (HasImmediateInput(instr, 0)) { 460 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); 461 __ jmp(code, RelocInfo::CODE_TARGET); 462 } else { 463 Register reg = i.InputRegister(0); 464 __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag)); 465 __ jmp(reg); 466 } 467 frame_access_state()->ClearSPDelta(); 468 break; 469 } 470 case kArchTailCallAddress: { 471 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 472 AssembleDeconstructActivationRecord(stack_param_delta); 473 CHECK(!HasImmediateInput(instr, 0)); 474 Register reg = i.InputRegister(0); 475 __ jmp(reg); 476 frame_access_state()->ClearSPDelta(); 477 break; 478 } 479 case kArchCallJSFunction: { 480 EnsureSpaceForLazyDeopt(); 481 Register func = i.InputRegister(0); 482 if (FLAG_debug_code) { 483 // Check the function's context matches the context argument. 484 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); 485 __ Assert(equal, kWrongFunctionContext); 486 } 487 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset)); 488 RecordCallPosition(instr); 489 frame_access_state()->ClearSPDelta(); 490 break; 491 } 492 case kArchTailCallJSFunctionFromJSFunction: 493 case kArchTailCallJSFunction: { 494 Register func = i.InputRegister(0); 495 if (FLAG_debug_code) { 496 // Check the function's context matches the context argument. 497 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); 498 __ Assert(equal, kWrongFunctionContext); 499 } 500 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); 501 AssembleDeconstructActivationRecord(stack_param_delta); 502 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) { 503 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, 504 no_reg, no_reg, no_reg); 505 } 506 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset)); 507 frame_access_state()->ClearSPDelta(); 508 break; 509 } 510 case kArchPrepareCallCFunction: { 511 // Frame alignment requires using FP-relative frame addressing. 512 frame_access_state()->SetFrameAccessToFP(); 513 int const num_parameters = MiscField::decode(instr->opcode()); 514 __ PrepareCallCFunction(num_parameters, i.TempRegister(0)); 515 break; 516 } 517 case kArchPrepareTailCall: 518 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1)); 519 break; 520 case kArchCallCFunction: { 521 int const num_parameters = MiscField::decode(instr->opcode()); 522 if (HasImmediateInput(instr, 0)) { 523 ExternalReference ref = i.InputExternalReference(0); 524 __ CallCFunction(ref, num_parameters); 525 } else { 526 Register func = i.InputRegister(0); 527 __ CallCFunction(func, num_parameters); 528 } 529 frame_access_state()->SetFrameAccessToDefault(); 530 frame_access_state()->ClearSPDelta(); 531 break; 532 } 533 case kArchJmp: 534 AssembleArchJump(i.InputRpo(0)); 535 break; 536 case kArchLookupSwitch: 537 AssembleArchLookupSwitch(instr); 538 break; 539 case kArchTableSwitch: 540 AssembleArchTableSwitch(instr); 541 break; 542 case kArchNop: 543 case kArchThrowTerminator: 544 // don't emit code for nops. 545 break; 546 case kArchDeoptimize: { 547 int deopt_state_id = 548 BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); 549 Deoptimizer::BailoutType bailout_type = 550 Deoptimizer::BailoutType(MiscField::decode(instr->opcode())); 551 CodeGenResult result = 552 AssembleDeoptimizerCall(deopt_state_id, bailout_type); 553 if (result != kSuccess) return result; 554 break; 555 } 556 case kArchRet: 557 AssembleReturn(); 558 break; 559 case kArchStackPointer: 560 __ mov(i.OutputRegister(), esp); 561 break; 562 case kArchFramePointer: 563 __ mov(i.OutputRegister(), ebp); 564 break; 565 case kArchParentFramePointer: 566 if (frame_access_state()->has_frame()) { 567 __ mov(i.OutputRegister(), Operand(ebp, 0)); 568 } else { 569 __ mov(i.OutputRegister(), ebp); 570 } 571 break; 572 case kArchTruncateDoubleToI: { 573 auto result = i.OutputRegister(); 574 auto input = i.InputDoubleRegister(0); 575 auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input); 576 __ cvttsd2si(result, Operand(input)); 577 __ cmp(result, 1); 578 __ j(overflow, ool->entry()); 579 __ bind(ool->exit()); 580 break; 581 } 582 case kArchStoreWithWriteBarrier: { 583 RecordWriteMode mode = 584 static_cast<RecordWriteMode>(MiscField::decode(instr->opcode())); 585 Register object = i.InputRegister(0); 586 size_t index = 0; 587 Operand operand = i.MemoryOperand(&index); 588 Register value = i.InputRegister(index); 589 Register scratch0 = i.TempRegister(0); 590 Register scratch1 = i.TempRegister(1); 591 auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value, 592 scratch0, scratch1, mode); 593 __ mov(operand, value); 594 __ CheckPageFlag(object, scratch0, 595 MemoryChunk::kPointersFromHereAreInterestingMask, 596 not_zero, ool->entry()); 597 __ bind(ool->exit()); 598 break; 599 } 600 case kArchStackSlot: { 601 FrameOffset offset = 602 frame_access_state()->GetFrameOffset(i.InputInt32(0)); 603 Register base; 604 if (offset.from_stack_pointer()) { 605 base = esp; 606 } else { 607 base = ebp; 608 } 609 __ lea(i.OutputRegister(), Operand(base, offset.offset())); 610 break; 611 } 612 case kIA32Add: 613 if (HasImmediateInput(instr, 1)) { 614 __ add(i.InputOperand(0), i.InputImmediate(1)); 615 } else { 616 __ add(i.InputRegister(0), i.InputOperand(1)); 617 } 618 break; 619 case kIA32And: 620 if (HasImmediateInput(instr, 1)) { 621 __ and_(i.InputOperand(0), i.InputImmediate(1)); 622 } else { 623 __ and_(i.InputRegister(0), i.InputOperand(1)); 624 } 625 break; 626 case kIA32Cmp: 627 ASSEMBLE_COMPARE(cmp); 628 break; 629 case kIA32Cmp16: 630 ASSEMBLE_COMPARE(cmpw); 631 break; 632 case kIA32Cmp8: 633 ASSEMBLE_COMPARE(cmpb); 634 break; 635 case kIA32Test: 636 ASSEMBLE_COMPARE(test); 637 break; 638 case kIA32Test16: 639 ASSEMBLE_COMPARE(test_w); 640 break; 641 case kIA32Test8: 642 ASSEMBLE_COMPARE(test_b); 643 break; 644 case kIA32Imul: 645 if (HasImmediateInput(instr, 1)) { 646 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1)); 647 } else { 648 __ imul(i.OutputRegister(), i.InputOperand(1)); 649 } 650 break; 651 case kIA32ImulHigh: 652 __ imul(i.InputRegister(1)); 653 break; 654 case kIA32UmulHigh: 655 __ mul(i.InputRegister(1)); 656 break; 657 case kIA32Idiv: 658 __ cdq(); 659 __ idiv(i.InputOperand(1)); 660 break; 661 case kIA32Udiv: 662 __ Move(edx, Immediate(0)); 663 __ div(i.InputOperand(1)); 664 break; 665 case kIA32Not: 666 __ not_(i.OutputOperand()); 667 break; 668 case kIA32Neg: 669 __ neg(i.OutputOperand()); 670 break; 671 case kIA32Or: 672 if (HasImmediateInput(instr, 1)) { 673 __ or_(i.InputOperand(0), i.InputImmediate(1)); 674 } else { 675 __ or_(i.InputRegister(0), i.InputOperand(1)); 676 } 677 break; 678 case kIA32Xor: 679 if (HasImmediateInput(instr, 1)) { 680 __ xor_(i.InputOperand(0), i.InputImmediate(1)); 681 } else { 682 __ xor_(i.InputRegister(0), i.InputOperand(1)); 683 } 684 break; 685 case kIA32Sub: 686 if (HasImmediateInput(instr, 1)) { 687 __ sub(i.InputOperand(0), i.InputImmediate(1)); 688 } else { 689 __ sub(i.InputRegister(0), i.InputOperand(1)); 690 } 691 break; 692 case kIA32Shl: 693 if (HasImmediateInput(instr, 1)) { 694 __ shl(i.OutputOperand(), i.InputInt5(1)); 695 } else { 696 __ shl_cl(i.OutputOperand()); 697 } 698 break; 699 case kIA32Shr: 700 if (HasImmediateInput(instr, 1)) { 701 __ shr(i.OutputOperand(), i.InputInt5(1)); 702 } else { 703 __ shr_cl(i.OutputOperand()); 704 } 705 break; 706 case kIA32Sar: 707 if (HasImmediateInput(instr, 1)) { 708 __ sar(i.OutputOperand(), i.InputInt5(1)); 709 } else { 710 __ sar_cl(i.OutputOperand()); 711 } 712 break; 713 case kIA32AddPair: { 714 // i.OutputRegister(0) == i.InputRegister(0) ... left low word. 715 // i.InputRegister(1) ... left high word. 716 // i.InputRegister(2) ... right low word. 717 // i.InputRegister(3) ... right high word. 718 bool use_temp = false; 719 if (i.OutputRegister(0).code() == i.InputRegister(1).code() || 720 i.OutputRegister(0).code() == i.InputRegister(3).code()) { 721 // We cannot write to the output register directly, because it would 722 // overwrite an input for adc. We have to use the temp register. 723 use_temp = true; 724 __ Move(i.TempRegister(0), i.InputRegister(0)); 725 __ add(i.TempRegister(0), i.InputRegister(2)); 726 } else { 727 __ add(i.OutputRegister(0), i.InputRegister(2)); 728 } 729 __ adc(i.InputRegister(1), Operand(i.InputRegister(3))); 730 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) { 731 __ Move(i.OutputRegister(1), i.InputRegister(1)); 732 } 733 if (use_temp) { 734 __ Move(i.OutputRegister(0), i.TempRegister(0)); 735 } 736 break; 737 } 738 case kIA32SubPair: { 739 // i.OutputRegister(0) == i.InputRegister(0) ... left low word. 740 // i.InputRegister(1) ... left high word. 741 // i.InputRegister(2) ... right low word. 742 // i.InputRegister(3) ... right high word. 743 bool use_temp = false; 744 if (i.OutputRegister(0).code() == i.InputRegister(1).code() || 745 i.OutputRegister(0).code() == i.InputRegister(3).code()) { 746 // We cannot write to the output register directly, because it would 747 // overwrite an input for adc. We have to use the temp register. 748 use_temp = true; 749 __ Move(i.TempRegister(0), i.InputRegister(0)); 750 __ sub(i.TempRegister(0), i.InputRegister(2)); 751 } else { 752 __ sub(i.OutputRegister(0), i.InputRegister(2)); 753 } 754 __ sbb(i.InputRegister(1), Operand(i.InputRegister(3))); 755 if (i.OutputRegister(1).code() != i.InputRegister(1).code()) { 756 __ Move(i.OutputRegister(1), i.InputRegister(1)); 757 } 758 if (use_temp) { 759 __ Move(i.OutputRegister(0), i.TempRegister(0)); 760 } 761 break; 762 } 763 case kIA32MulPair: { 764 __ imul(i.OutputRegister(1), i.InputOperand(0)); 765 __ mov(i.TempRegister(0), i.InputOperand(1)); 766 __ imul(i.TempRegister(0), i.InputOperand(2)); 767 __ add(i.OutputRegister(1), i.TempRegister(0)); 768 __ mov(i.OutputRegister(0), i.InputOperand(0)); 769 // Multiplies the low words and stores them in eax and edx. 770 __ mul(i.InputRegister(2)); 771 __ add(i.OutputRegister(1), i.TempRegister(0)); 772 773 break; 774 } 775 case kIA32ShlPair: 776 if (HasImmediateInput(instr, 2)) { 777 __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); 778 } else { 779 // Shift has been loaded into CL by the register allocator. 780 __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0)); 781 } 782 break; 783 case kIA32ShrPair: 784 if (HasImmediateInput(instr, 2)) { 785 __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); 786 } else { 787 // Shift has been loaded into CL by the register allocator. 788 __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0)); 789 } 790 break; 791 case kIA32SarPair: 792 if (HasImmediateInput(instr, 2)) { 793 __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); 794 } else { 795 // Shift has been loaded into CL by the register allocator. 796 __ SarPair_cl(i.InputRegister(1), i.InputRegister(0)); 797 } 798 break; 799 case kIA32Ror: 800 if (HasImmediateInput(instr, 1)) { 801 __ ror(i.OutputOperand(), i.InputInt5(1)); 802 } else { 803 __ ror_cl(i.OutputOperand()); 804 } 805 break; 806 case kIA32Lzcnt: 807 __ Lzcnt(i.OutputRegister(), i.InputOperand(0)); 808 break; 809 case kIA32Tzcnt: 810 __ Tzcnt(i.OutputRegister(), i.InputOperand(0)); 811 break; 812 case kIA32Popcnt: 813 __ Popcnt(i.OutputRegister(), i.InputOperand(0)); 814 break; 815 case kSSEFloat32Cmp: 816 __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1)); 817 break; 818 case kSSEFloat32Add: 819 __ addss(i.InputDoubleRegister(0), i.InputOperand(1)); 820 break; 821 case kSSEFloat32Sub: 822 __ subss(i.InputDoubleRegister(0), i.InputOperand(1)); 823 break; 824 case kSSEFloat32Mul: 825 __ mulss(i.InputDoubleRegister(0), i.InputOperand(1)); 826 break; 827 case kSSEFloat32Div: 828 __ divss(i.InputDoubleRegister(0), i.InputOperand(1)); 829 // Don't delete this mov. It may improve performance on some CPUs, 830 // when there is a (v)mulss depending on the result. 831 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); 832 break; 833 case kSSEFloat32Max: 834 __ maxss(i.InputDoubleRegister(0), i.InputOperand(1)); 835 break; 836 case kSSEFloat32Min: 837 __ minss(i.InputDoubleRegister(0), i.InputOperand(1)); 838 break; 839 case kSSEFloat32Sqrt: 840 __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0)); 841 break; 842 case kSSEFloat32Abs: { 843 // TODO(bmeurer): Use 128-bit constants. 844 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 845 __ psrlq(kScratchDoubleReg, 33); 846 __ andps(i.OutputDoubleRegister(), kScratchDoubleReg); 847 break; 848 } 849 case kSSEFloat32Neg: { 850 // TODO(bmeurer): Use 128-bit constants. 851 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 852 __ psllq(kScratchDoubleReg, 31); 853 __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg); 854 break; 855 } 856 case kSSEFloat32Round: { 857 CpuFeatureScope sse_scope(masm(), SSE4_1); 858 RoundingMode const mode = 859 static_cast<RoundingMode>(MiscField::decode(instr->opcode())); 860 __ roundss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode); 861 break; 862 } 863 case kSSEFloat64Cmp: 864 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1)); 865 break; 866 case kSSEFloat64Add: 867 __ addsd(i.InputDoubleRegister(0), i.InputOperand(1)); 868 break; 869 case kSSEFloat64Sub: 870 __ subsd(i.InputDoubleRegister(0), i.InputOperand(1)); 871 break; 872 case kSSEFloat64Mul: 873 __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1)); 874 break; 875 case kSSEFloat64Div: 876 __ divsd(i.InputDoubleRegister(0), i.InputOperand(1)); 877 // Don't delete this mov. It may improve performance on some CPUs, 878 // when there is a (v)mulsd depending on the result. 879 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); 880 break; 881 case kSSEFloat64Max: 882 __ maxsd(i.InputDoubleRegister(0), i.InputOperand(1)); 883 break; 884 case kSSEFloat64Min: 885 __ minsd(i.InputDoubleRegister(0), i.InputOperand(1)); 886 break; 887 case kSSEFloat64Mod: { 888 // TODO(dcarney): alignment is wrong. 889 __ sub(esp, Immediate(kDoubleSize)); 890 // Move values to st(0) and st(1). 891 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1)); 892 __ fld_d(Operand(esp, 0)); 893 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0)); 894 __ fld_d(Operand(esp, 0)); 895 // Loop while fprem isn't done. 896 Label mod_loop; 897 __ bind(&mod_loop); 898 // This instructions traps on all kinds inputs, but we are assuming the 899 // floating point control word is set to ignore them all. 900 __ fprem(); 901 // The following 2 instruction implicitly use eax. 902 __ fnstsw_ax(); 903 __ sahf(); 904 __ j(parity_even, &mod_loop); 905 // Move output to stack and clean up. 906 __ fstp(1); 907 __ fstp_d(Operand(esp, 0)); 908 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0)); 909 __ add(esp, Immediate(kDoubleSize)); 910 break; 911 } 912 case kSSEFloat64Abs: { 913 // TODO(bmeurer): Use 128-bit constants. 914 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 915 __ psrlq(kScratchDoubleReg, 1); 916 __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg); 917 break; 918 } 919 case kSSEFloat64Neg: { 920 // TODO(bmeurer): Use 128-bit constants. 921 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 922 __ psllq(kScratchDoubleReg, 63); 923 __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg); 924 break; 925 } 926 case kSSEFloat64Sqrt: 927 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0)); 928 break; 929 case kSSEFloat64Round: { 930 CpuFeatureScope sse_scope(masm(), SSE4_1); 931 RoundingMode const mode = 932 static_cast<RoundingMode>(MiscField::decode(instr->opcode())); 933 __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode); 934 break; 935 } 936 case kSSEFloat32ToFloat64: 937 __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0)); 938 break; 939 case kSSEFloat64ToFloat32: 940 __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0)); 941 break; 942 case kSSEFloat32ToInt32: 943 __ cvttss2si(i.OutputRegister(), i.InputOperand(0)); 944 break; 945 case kSSEFloat32ToUint32: { 946 Label success; 947 __ cvttss2si(i.OutputRegister(), i.InputOperand(0)); 948 __ test(i.OutputRegister(), i.OutputRegister()); 949 __ j(positive, &success); 950 __ Move(kScratchDoubleReg, static_cast<float>(INT32_MIN)); 951 __ addss(kScratchDoubleReg, i.InputOperand(0)); 952 __ cvttss2si(i.OutputRegister(), kScratchDoubleReg); 953 __ or_(i.OutputRegister(), Immediate(0x80000000)); 954 __ bind(&success); 955 break; 956 } 957 case kSSEFloat64ToInt32: 958 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0)); 959 break; 960 case kSSEFloat64ToUint32: { 961 __ Move(kScratchDoubleReg, -2147483648.0); 962 __ addsd(kScratchDoubleReg, i.InputOperand(0)); 963 __ cvttsd2si(i.OutputRegister(), kScratchDoubleReg); 964 __ add(i.OutputRegister(), Immediate(0x80000000)); 965 break; 966 } 967 case kSSEInt32ToFloat32: 968 __ cvtsi2ss(i.OutputDoubleRegister(), i.InputOperand(0)); 969 break; 970 case kSSEUint32ToFloat32: { 971 Register scratch0 = i.TempRegister(0); 972 Register scratch1 = i.TempRegister(1); 973 __ mov(scratch0, i.InputOperand(0)); 974 __ Cvtui2ss(i.OutputDoubleRegister(), scratch0, scratch1); 975 break; 976 } 977 case kSSEInt32ToFloat64: 978 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0)); 979 break; 980 case kSSEUint32ToFloat64: 981 __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0)); 982 break; 983 case kSSEFloat64ExtractLowWord32: 984 if (instr->InputAt(0)->IsFPStackSlot()) { 985 __ mov(i.OutputRegister(), i.InputOperand(0)); 986 } else { 987 __ movd(i.OutputRegister(), i.InputDoubleRegister(0)); 988 } 989 break; 990 case kSSEFloat64ExtractHighWord32: 991 if (instr->InputAt(0)->IsFPStackSlot()) { 992 __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); 993 } else { 994 __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1); 995 } 996 break; 997 case kSSEFloat64InsertLowWord32: 998 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0); 999 break; 1000 case kSSEFloat64InsertHighWord32: 1001 __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1); 1002 break; 1003 case kSSEFloat64LoadLowWord32: 1004 __ movd(i.OutputDoubleRegister(), i.InputOperand(0)); 1005 break; 1006 case kAVXFloat32Add: { 1007 CpuFeatureScope avx_scope(masm(), AVX); 1008 __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1009 i.InputOperand(1)); 1010 break; 1011 } 1012 case kAVXFloat32Sub: { 1013 CpuFeatureScope avx_scope(masm(), AVX); 1014 __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1015 i.InputOperand(1)); 1016 break; 1017 } 1018 case kAVXFloat32Mul: { 1019 CpuFeatureScope avx_scope(masm(), AVX); 1020 __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1021 i.InputOperand(1)); 1022 break; 1023 } 1024 case kAVXFloat32Div: { 1025 CpuFeatureScope avx_scope(masm(), AVX); 1026 __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1027 i.InputOperand(1)); 1028 // Don't delete this mov. It may improve performance on some CPUs, 1029 // when there is a (v)mulss depending on the result. 1030 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); 1031 break; 1032 } 1033 case kAVXFloat32Max: { 1034 CpuFeatureScope avx_scope(masm(), AVX); 1035 __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1036 i.InputOperand(1)); 1037 break; 1038 } 1039 case kAVXFloat32Min: { 1040 CpuFeatureScope avx_scope(masm(), AVX); 1041 __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1042 i.InputOperand(1)); 1043 break; 1044 } 1045 case kAVXFloat64Add: { 1046 CpuFeatureScope avx_scope(masm(), AVX); 1047 __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1048 i.InputOperand(1)); 1049 break; 1050 } 1051 case kAVXFloat64Sub: { 1052 CpuFeatureScope avx_scope(masm(), AVX); 1053 __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1054 i.InputOperand(1)); 1055 break; 1056 } 1057 case kAVXFloat64Mul: { 1058 CpuFeatureScope avx_scope(masm(), AVX); 1059 __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1060 i.InputOperand(1)); 1061 break; 1062 } 1063 case kAVXFloat64Div: { 1064 CpuFeatureScope avx_scope(masm(), AVX); 1065 __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1066 i.InputOperand(1)); 1067 // Don't delete this mov. It may improve performance on some CPUs, 1068 // when there is a (v)mulsd depending on the result. 1069 __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); 1070 break; 1071 } 1072 case kAVXFloat64Max: { 1073 CpuFeatureScope avx_scope(masm(), AVX); 1074 __ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1075 i.InputOperand(1)); 1076 break; 1077 } 1078 case kAVXFloat64Min: { 1079 CpuFeatureScope avx_scope(masm(), AVX); 1080 __ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), 1081 i.InputOperand(1)); 1082 break; 1083 } 1084 case kAVXFloat32Abs: { 1085 // TODO(bmeurer): Use RIP relative 128-bit constants. 1086 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 1087 __ psrlq(kScratchDoubleReg, 33); 1088 CpuFeatureScope avx_scope(masm(), AVX); 1089 __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); 1090 break; 1091 } 1092 case kAVXFloat32Neg: { 1093 // TODO(bmeurer): Use RIP relative 128-bit constants. 1094 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 1095 __ psllq(kScratchDoubleReg, 31); 1096 CpuFeatureScope avx_scope(masm(), AVX); 1097 __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); 1098 break; 1099 } 1100 case kAVXFloat64Abs: { 1101 // TODO(bmeurer): Use RIP relative 128-bit constants. 1102 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 1103 __ psrlq(kScratchDoubleReg, 1); 1104 CpuFeatureScope avx_scope(masm(), AVX); 1105 __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); 1106 break; 1107 } 1108 case kAVXFloat64Neg: { 1109 // TODO(bmeurer): Use RIP relative 128-bit constants. 1110 __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); 1111 __ psllq(kScratchDoubleReg, 63); 1112 CpuFeatureScope avx_scope(masm(), AVX); 1113 __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); 1114 break; 1115 } 1116 case kIA32Movsxbl: 1117 __ movsx_b(i.OutputRegister(), i.MemoryOperand()); 1118 break; 1119 case kIA32Movzxbl: 1120 __ movzx_b(i.OutputRegister(), i.MemoryOperand()); 1121 break; 1122 case kIA32Movb: { 1123 size_t index = 0; 1124 Operand operand = i.MemoryOperand(&index); 1125 if (HasImmediateInput(instr, index)) { 1126 __ mov_b(operand, i.InputInt8(index)); 1127 } else { 1128 __ mov_b(operand, i.InputRegister(index)); 1129 } 1130 break; 1131 } 1132 case kIA32Movsxwl: 1133 __ movsx_w(i.OutputRegister(), i.MemoryOperand()); 1134 break; 1135 case kIA32Movzxwl: 1136 __ movzx_w(i.OutputRegister(), i.MemoryOperand()); 1137 break; 1138 case kIA32Movw: { 1139 size_t index = 0; 1140 Operand operand = i.MemoryOperand(&index); 1141 if (HasImmediateInput(instr, index)) { 1142 __ mov_w(operand, i.InputInt16(index)); 1143 } else { 1144 __ mov_w(operand, i.InputRegister(index)); 1145 } 1146 break; 1147 } 1148 case kIA32Movl: 1149 if (instr->HasOutput()) { 1150 __ mov(i.OutputRegister(), i.MemoryOperand()); 1151 } else { 1152 size_t index = 0; 1153 Operand operand = i.MemoryOperand(&index); 1154 if (HasImmediateInput(instr, index)) { 1155 __ mov(operand, i.InputImmediate(index)); 1156 } else { 1157 __ mov(operand, i.InputRegister(index)); 1158 } 1159 } 1160 break; 1161 case kIA32Movsd: 1162 if (instr->HasOutput()) { 1163 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); 1164 } else { 1165 size_t index = 0; 1166 Operand operand = i.MemoryOperand(&index); 1167 __ movsd(operand, i.InputDoubleRegister(index)); 1168 } 1169 break; 1170 case kIA32Movss: 1171 if (instr->HasOutput()) { 1172 __ movss(i.OutputDoubleRegister(), i.MemoryOperand()); 1173 } else { 1174 size_t index = 0; 1175 Operand operand = i.MemoryOperand(&index); 1176 __ movss(operand, i.InputDoubleRegister(index)); 1177 } 1178 break; 1179 case kIA32BitcastFI: 1180 if (instr->InputAt(0)->IsFPStackSlot()) { 1181 __ mov(i.OutputRegister(), i.InputOperand(0)); 1182 } else { 1183 __ movd(i.OutputRegister(), i.InputDoubleRegister(0)); 1184 } 1185 break; 1186 case kIA32BitcastIF: 1187 if (instr->InputAt(0)->IsRegister()) { 1188 __ movd(i.OutputDoubleRegister(), i.InputRegister(0)); 1189 } else { 1190 __ movss(i.OutputDoubleRegister(), i.InputOperand(0)); 1191 } 1192 break; 1193 case kIA32Lea: { 1194 AddressingMode mode = AddressingModeField::decode(instr->opcode()); 1195 // Shorten "leal" to "addl", "subl" or "shll" if the register allocation 1196 // and addressing mode just happens to work out. The "addl"/"subl" forms 1197 // in these cases are faster based on measurements. 1198 if (mode == kMode_MI) { 1199 __ Move(i.OutputRegister(), Immediate(i.InputInt32(0))); 1200 } else if (i.InputRegister(0).is(i.OutputRegister())) { 1201 if (mode == kMode_MRI) { 1202 int32_t constant_summand = i.InputInt32(1); 1203 if (constant_summand > 0) { 1204 __ add(i.OutputRegister(), Immediate(constant_summand)); 1205 } else if (constant_summand < 0) { 1206 __ sub(i.OutputRegister(), Immediate(-constant_summand)); 1207 } 1208 } else if (mode == kMode_MR1) { 1209 if (i.InputRegister(1).is(i.OutputRegister())) { 1210 __ shl(i.OutputRegister(), 1); 1211 } else { 1212 __ lea(i.OutputRegister(), i.MemoryOperand()); 1213 } 1214 } else if (mode == kMode_M2) { 1215 __ shl(i.OutputRegister(), 1); 1216 } else if (mode == kMode_M4) { 1217 __ shl(i.OutputRegister(), 2); 1218 } else if (mode == kMode_M8) { 1219 __ shl(i.OutputRegister(), 3); 1220 } else { 1221 __ lea(i.OutputRegister(), i.MemoryOperand()); 1222 } 1223 } else { 1224 __ lea(i.OutputRegister(), i.MemoryOperand()); 1225 } 1226 break; 1227 } 1228 case kIA32PushFloat32: 1229 if (instr->InputAt(0)->IsFPRegister()) { 1230 __ sub(esp, Immediate(kDoubleSize)); 1231 __ movss(Operand(esp, 0), i.InputDoubleRegister(0)); 1232 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1233 } else if (HasImmediateInput(instr, 0)) { 1234 __ Move(kScratchDoubleReg, i.InputDouble(0)); 1235 __ sub(esp, Immediate(kDoubleSize)); 1236 __ movss(Operand(esp, 0), kScratchDoubleReg); 1237 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1238 } else { 1239 __ movsd(kScratchDoubleReg, i.InputOperand(0)); 1240 __ sub(esp, Immediate(kDoubleSize)); 1241 __ movss(Operand(esp, 0), kScratchDoubleReg); 1242 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1243 } 1244 break; 1245 case kIA32PushFloat64: 1246 if (instr->InputAt(0)->IsFPRegister()) { 1247 __ sub(esp, Immediate(kDoubleSize)); 1248 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0)); 1249 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1250 } else if (HasImmediateInput(instr, 0)) { 1251 __ Move(kScratchDoubleReg, i.InputDouble(0)); 1252 __ sub(esp, Immediate(kDoubleSize)); 1253 __ movsd(Operand(esp, 0), kScratchDoubleReg); 1254 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1255 } else { 1256 __ movsd(kScratchDoubleReg, i.InputOperand(0)); 1257 __ sub(esp, Immediate(kDoubleSize)); 1258 __ movsd(Operand(esp, 0), kScratchDoubleReg); 1259 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1260 } 1261 break; 1262 case kIA32Push: 1263 if (instr->InputAt(0)->IsFPRegister()) { 1264 __ sub(esp, Immediate(kDoubleSize)); 1265 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0)); 1266 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); 1267 } else if (HasImmediateInput(instr, 0)) { 1268 __ push(i.InputImmediate(0)); 1269 frame_access_state()->IncreaseSPDelta(1); 1270 } else { 1271 __ push(i.InputOperand(0)); 1272 frame_access_state()->IncreaseSPDelta(1); 1273 } 1274 break; 1275 case kIA32Poke: { 1276 int const slot = MiscField::decode(instr->opcode()); 1277 if (HasImmediateInput(instr, 0)) { 1278 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0)); 1279 } else { 1280 __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0)); 1281 } 1282 break; 1283 } 1284 case kIA32Xchgb: { 1285 size_t index = 0; 1286 Operand operand = i.MemoryOperand(&index); 1287 __ xchg_b(i.InputRegister(index), operand); 1288 break; 1289 } 1290 case kIA32Xchgw: { 1291 size_t index = 0; 1292 Operand operand = i.MemoryOperand(&index); 1293 __ xchg_w(i.InputRegister(index), operand); 1294 break; 1295 } 1296 case kIA32Xchgl: { 1297 size_t index = 0; 1298 Operand operand = i.MemoryOperand(&index); 1299 __ xchg(i.InputRegister(index), operand); 1300 break; 1301 } 1302 case kCheckedLoadInt8: 1303 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b); 1304 break; 1305 case kCheckedLoadUint8: 1306 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b); 1307 break; 1308 case kCheckedLoadInt16: 1309 ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w); 1310 break; 1311 case kCheckedLoadUint16: 1312 ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w); 1313 break; 1314 case kCheckedLoadWord32: 1315 ASSEMBLE_CHECKED_LOAD_INTEGER(mov); 1316 break; 1317 case kCheckedLoadFloat32: 1318 ASSEMBLE_CHECKED_LOAD_FLOAT(movss); 1319 break; 1320 case kCheckedLoadFloat64: 1321 ASSEMBLE_CHECKED_LOAD_FLOAT(movsd); 1322 break; 1323 case kCheckedStoreWord8: 1324 ASSEMBLE_CHECKED_STORE_INTEGER(mov_b); 1325 break; 1326 case kCheckedStoreWord16: 1327 ASSEMBLE_CHECKED_STORE_INTEGER(mov_w); 1328 break; 1329 case kCheckedStoreWord32: 1330 ASSEMBLE_CHECKED_STORE_INTEGER(mov); 1331 break; 1332 case kCheckedStoreFloat32: 1333 ASSEMBLE_CHECKED_STORE_FLOAT(movss); 1334 break; 1335 case kCheckedStoreFloat64: 1336 ASSEMBLE_CHECKED_STORE_FLOAT(movsd); 1337 break; 1338 case kIA32StackCheck: { 1339 ExternalReference const stack_limit = 1340 ExternalReference::address_of_stack_limit(isolate()); 1341 __ cmp(esp, Operand::StaticVariable(stack_limit)); 1342 break; 1343 } 1344 case kCheckedLoadWord64: 1345 case kCheckedStoreWord64: 1346 UNREACHABLE(); // currently unsupported checked int64 load/store. 1347 break; 1348 case kAtomicLoadInt8: 1349 case kAtomicLoadUint8: 1350 case kAtomicLoadInt16: 1351 case kAtomicLoadUint16: 1352 case kAtomicLoadWord32: 1353 case kAtomicStoreWord8: 1354 case kAtomicStoreWord16: 1355 case kAtomicStoreWord32: 1356 UNREACHABLE(); // Won't be generated by instruction selector. 1357 break; 1358 } 1359 return kSuccess; 1360} // NOLINT(readability/fn_size) 1361 1362 1363// Assembles a branch after an instruction. 1364void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { 1365 IA32OperandConverter i(this, instr); 1366 Label::Distance flabel_distance = 1367 branch->fallthru ? Label::kNear : Label::kFar; 1368 Label* tlabel = branch->true_label; 1369 Label* flabel = branch->false_label; 1370 switch (branch->condition) { 1371 case kUnorderedEqual: 1372 __ j(parity_even, flabel, flabel_distance); 1373 // Fall through. 1374 case kEqual: 1375 __ j(equal, tlabel); 1376 break; 1377 case kUnorderedNotEqual: 1378 __ j(parity_even, tlabel); 1379 // Fall through. 1380 case kNotEqual: 1381 __ j(not_equal, tlabel); 1382 break; 1383 case kSignedLessThan: 1384 __ j(less, tlabel); 1385 break; 1386 case kSignedGreaterThanOrEqual: 1387 __ j(greater_equal, tlabel); 1388 break; 1389 case kSignedLessThanOrEqual: 1390 __ j(less_equal, tlabel); 1391 break; 1392 case kSignedGreaterThan: 1393 __ j(greater, tlabel); 1394 break; 1395 case kUnsignedLessThan: 1396 __ j(below, tlabel); 1397 break; 1398 case kUnsignedGreaterThanOrEqual: 1399 __ j(above_equal, tlabel); 1400 break; 1401 case kUnsignedLessThanOrEqual: 1402 __ j(below_equal, tlabel); 1403 break; 1404 case kUnsignedGreaterThan: 1405 __ j(above, tlabel); 1406 break; 1407 case kOverflow: 1408 __ j(overflow, tlabel); 1409 break; 1410 case kNotOverflow: 1411 __ j(no_overflow, tlabel); 1412 break; 1413 default: 1414 UNREACHABLE(); 1415 break; 1416 } 1417 // Add a jump if not falling through to the next block. 1418 if (!branch->fallthru) __ jmp(flabel); 1419} 1420 1421 1422void CodeGenerator::AssembleArchJump(RpoNumber target) { 1423 if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target)); 1424} 1425 1426 1427// Assembles boolean materializations after an instruction. 1428void CodeGenerator::AssembleArchBoolean(Instruction* instr, 1429 FlagsCondition condition) { 1430 IA32OperandConverter i(this, instr); 1431 Label done; 1432 1433 // Materialize a full 32-bit 1 or 0 value. The result register is always the 1434 // last output of the instruction. 1435 Label check; 1436 DCHECK_NE(0u, instr->OutputCount()); 1437 Register reg = i.OutputRegister(instr->OutputCount() - 1); 1438 Condition cc = no_condition; 1439 switch (condition) { 1440 case kUnorderedEqual: 1441 __ j(parity_odd, &check, Label::kNear); 1442 __ Move(reg, Immediate(0)); 1443 __ jmp(&done, Label::kNear); 1444 // Fall through. 1445 case kEqual: 1446 cc = equal; 1447 break; 1448 case kUnorderedNotEqual: 1449 __ j(parity_odd, &check, Label::kNear); 1450 __ mov(reg, Immediate(1)); 1451 __ jmp(&done, Label::kNear); 1452 // Fall through. 1453 case kNotEqual: 1454 cc = not_equal; 1455 break; 1456 case kSignedLessThan: 1457 cc = less; 1458 break; 1459 case kSignedGreaterThanOrEqual: 1460 cc = greater_equal; 1461 break; 1462 case kSignedLessThanOrEqual: 1463 cc = less_equal; 1464 break; 1465 case kSignedGreaterThan: 1466 cc = greater; 1467 break; 1468 case kUnsignedLessThan: 1469 cc = below; 1470 break; 1471 case kUnsignedGreaterThanOrEqual: 1472 cc = above_equal; 1473 break; 1474 case kUnsignedLessThanOrEqual: 1475 cc = below_equal; 1476 break; 1477 case kUnsignedGreaterThan: 1478 cc = above; 1479 break; 1480 case kOverflow: 1481 cc = overflow; 1482 break; 1483 case kNotOverflow: 1484 cc = no_overflow; 1485 break; 1486 default: 1487 UNREACHABLE(); 1488 break; 1489 } 1490 __ bind(&check); 1491 if (reg.is_byte_register()) { 1492 // setcc for byte registers (al, bl, cl, dl). 1493 __ setcc(cc, reg); 1494 __ movzx_b(reg, reg); 1495 } else { 1496 // Emit a branch to set a register to either 1 or 0. 1497 Label set; 1498 __ j(cc, &set, Label::kNear); 1499 __ Move(reg, Immediate(0)); 1500 __ jmp(&done, Label::kNear); 1501 __ bind(&set); 1502 __ mov(reg, Immediate(1)); 1503 } 1504 __ bind(&done); 1505} 1506 1507 1508void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { 1509 IA32OperandConverter i(this, instr); 1510 Register input = i.InputRegister(0); 1511 for (size_t index = 2; index < instr->InputCount(); index += 2) { 1512 __ cmp(input, Immediate(i.InputInt32(index + 0))); 1513 __ j(equal, GetLabel(i.InputRpo(index + 1))); 1514 } 1515 AssembleArchJump(i.InputRpo(1)); 1516} 1517 1518 1519void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { 1520 IA32OperandConverter i(this, instr); 1521 Register input = i.InputRegister(0); 1522 size_t const case_count = instr->InputCount() - 2; 1523 Label** cases = zone()->NewArray<Label*>(case_count); 1524 for (size_t index = 0; index < case_count; ++index) { 1525 cases[index] = GetLabel(i.InputRpo(index + 2)); 1526 } 1527 Label* const table = AddJumpTable(cases, case_count); 1528 __ cmp(input, Immediate(case_count)); 1529 __ j(above_equal, GetLabel(i.InputRpo(1))); 1530 __ jmp(Operand::JumpTable(input, times_4, table)); 1531} 1532 1533CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( 1534 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { 1535 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( 1536 isolate(), deoptimization_id, bailout_type); 1537 if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts; 1538 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY); 1539 return kSuccess; 1540} 1541 1542 1543// The calling convention for JSFunctions on IA32 passes arguments on the 1544// stack and the JSFunction and context in EDI and ESI, respectively, thus 1545// the steps of the call look as follows: 1546 1547// --{ before the call instruction }-------------------------------------------- 1548// | caller frame | 1549// ^ esp ^ ebp 1550 1551// --{ push arguments and setup ESI, EDI }-------------------------------------- 1552// | args + receiver | caller frame | 1553// ^ esp ^ ebp 1554// [edi = JSFunction, esi = context] 1555 1556// --{ call [edi + kCodeEntryOffset] }------------------------------------------ 1557// | RET | args + receiver | caller frame | 1558// ^ esp ^ ebp 1559 1560// =={ prologue of called function }============================================ 1561// --{ push ebp }--------------------------------------------------------------- 1562// | FP | RET | args + receiver | caller frame | 1563// ^ esp ^ ebp 1564 1565// --{ mov ebp, esp }----------------------------------------------------------- 1566// | FP | RET | args + receiver | caller frame | 1567// ^ ebp,esp 1568 1569// --{ push esi }--------------------------------------------------------------- 1570// | CTX | FP | RET | args + receiver | caller frame | 1571// ^esp ^ ebp 1572 1573// --{ push edi }--------------------------------------------------------------- 1574// | FNC | CTX | FP | RET | args + receiver | caller frame | 1575// ^esp ^ ebp 1576 1577// --{ subi esp, #N }----------------------------------------------------------- 1578// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame | 1579// ^esp ^ ebp 1580 1581// =={ body of called function }================================================ 1582 1583// =={ epilogue of called function }============================================ 1584// --{ mov esp, ebp }----------------------------------------------------------- 1585// | FP | RET | args + receiver | caller frame | 1586// ^ esp,ebp 1587 1588// --{ pop ebp }----------------------------------------------------------- 1589// | | RET | args + receiver | caller frame | 1590// ^ esp ^ ebp 1591 1592// --{ ret #A+1 }----------------------------------------------------------- 1593// | | caller frame | 1594// ^ esp ^ ebp 1595 1596 1597// Runtime function calls are accomplished by doing a stub call to the 1598// CEntryStub (a real code object). On IA32 passes arguments on the 1599// stack, the number of arguments in EAX, the address of the runtime function 1600// in EBX, and the context in ESI. 1601 1602// --{ before the call instruction }-------------------------------------------- 1603// | caller frame | 1604// ^ esp ^ ebp 1605 1606// --{ push arguments and setup EAX, EBX, and ESI }----------------------------- 1607// | args + receiver | caller frame | 1608// ^ esp ^ ebp 1609// [eax = #args, ebx = runtime function, esi = context] 1610 1611// --{ call #CEntryStub }------------------------------------------------------- 1612// | RET | args + receiver | caller frame | 1613// ^ esp ^ ebp 1614 1615// =={ body of runtime function }=============================================== 1616 1617// --{ runtime returns }-------------------------------------------------------- 1618// | caller frame | 1619// ^ esp ^ ebp 1620 1621// Other custom linkages (e.g. for calling directly into and out of C++) may 1622// need to save callee-saved registers on the stack, which is done in the 1623// function prologue of generated code. 1624 1625// --{ before the call instruction }-------------------------------------------- 1626// | caller frame | 1627// ^ esp ^ ebp 1628 1629// --{ set up arguments in registers on stack }--------------------------------- 1630// | args | caller frame | 1631// ^ esp ^ ebp 1632// [r0 = arg0, r1 = arg1, ...] 1633 1634// --{ call code }-------------------------------------------------------------- 1635// | RET | args | caller frame | 1636// ^ esp ^ ebp 1637 1638// =={ prologue of called function }============================================ 1639// --{ push ebp }--------------------------------------------------------------- 1640// | FP | RET | args | caller frame | 1641// ^ esp ^ ebp 1642 1643// --{ mov ebp, esp }----------------------------------------------------------- 1644// | FP | RET | args | caller frame | 1645// ^ ebp,esp 1646 1647// --{ save registers }--------------------------------------------------------- 1648// | regs | FP | RET | args | caller frame | 1649// ^ esp ^ ebp 1650 1651// --{ subi esp, #N }----------------------------------------------------------- 1652// | callee frame | regs | FP | RET | args | caller frame | 1653// ^esp ^ ebp 1654 1655// =={ body of called function }================================================ 1656 1657// =={ epilogue of called function }============================================ 1658// --{ restore registers }------------------------------------------------------ 1659// | regs | FP | RET | args | caller frame | 1660// ^ esp ^ ebp 1661 1662// --{ mov esp, ebp }----------------------------------------------------------- 1663// | FP | RET | args | caller frame | 1664// ^ esp,ebp 1665 1666// --{ pop ebp }---------------------------------------------------------------- 1667// | RET | args | caller frame | 1668// ^ esp ^ ebp 1669 1670void CodeGenerator::FinishFrame(Frame* frame) { 1671 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1672 const RegList saves = descriptor->CalleeSavedRegisters(); 1673 if (saves != 0) { // Save callee-saved registers. 1674 DCHECK(!info()->is_osr()); 1675 int pushed = 0; 1676 for (int i = Register::kNumRegisters - 1; i >= 0; i--) { 1677 if (!((1 << i) & saves)) continue; 1678 ++pushed; 1679 } 1680 frame->AllocateSavedCalleeRegisterSlots(pushed); 1681 } 1682} 1683 1684void CodeGenerator::AssembleConstructFrame() { 1685 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1686 if (frame_access_state()->has_frame()) { 1687 if (descriptor->IsCFunctionCall()) { 1688 __ push(ebp); 1689 __ mov(ebp, esp); 1690 } else if (descriptor->IsJSFunctionCall()) { 1691 __ Prologue(this->info()->GeneratePreagedPrologue()); 1692 } else { 1693 __ StubPrologue(info()->GetOutputStackFrameType()); 1694 } 1695 } 1696 1697 int shrink_slots = frame()->GetSpillSlotCount(); 1698 1699 if (info()->is_osr()) { 1700 // TurboFan OSR-compiled functions cannot be entered directly. 1701 __ Abort(kShouldNotDirectlyEnterOsrFunction); 1702 1703 // Unoptimized code jumps directly to this entrypoint while the unoptimized 1704 // frame is still on the stack. Optimized code uses OSR values directly from 1705 // the unoptimized frame. Thus, all that needs to be done is to allocate the 1706 // remaining stack slots. 1707 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 1708 osr_pc_offset_ = __ pc_offset(); 1709 shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); 1710 } 1711 1712 const RegList saves = descriptor->CalleeSavedRegisters(); 1713 if (shrink_slots > 0) { 1714 __ sub(esp, Immediate(shrink_slots * kPointerSize)); 1715 } 1716 1717 if (saves != 0) { // Save callee-saved registers. 1718 DCHECK(!info()->is_osr()); 1719 int pushed = 0; 1720 for (int i = Register::kNumRegisters - 1; i >= 0; i--) { 1721 if (!((1 << i) & saves)) continue; 1722 __ push(Register::from_code(i)); 1723 ++pushed; 1724 } 1725 } 1726} 1727 1728 1729void CodeGenerator::AssembleReturn() { 1730 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1731 1732 const RegList saves = descriptor->CalleeSavedRegisters(); 1733 // Restore registers. 1734 if (saves != 0) { 1735 for (int i = 0; i < Register::kNumRegisters; i++) { 1736 if (!((1 << i) & saves)) continue; 1737 __ pop(Register::from_code(i)); 1738 } 1739 } 1740 1741 if (descriptor->IsCFunctionCall()) { 1742 AssembleDeconstructFrame(); 1743 } else if (frame_access_state()->has_frame()) { 1744 // Canonicalize JSFunction return sites for now. 1745 if (return_label_.is_bound()) { 1746 __ jmp(&return_label_); 1747 return; 1748 } else { 1749 __ bind(&return_label_); 1750 AssembleDeconstructFrame(); 1751 } 1752 } 1753 size_t pop_size = descriptor->StackParameterCount() * kPointerSize; 1754 // Might need ecx for scratch if pop_size is too big. 1755 DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit()); 1756 __ Ret(static_cast<int>(pop_size), ecx); 1757} 1758 1759 1760void CodeGenerator::AssembleMove(InstructionOperand* source, 1761 InstructionOperand* destination) { 1762 IA32OperandConverter g(this, nullptr); 1763 // Dispatch on the source and destination operand kinds. Not all 1764 // combinations are possible. 1765 if (source->IsRegister()) { 1766 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 1767 Register src = g.ToRegister(source); 1768 Operand dst = g.ToOperand(destination); 1769 __ mov(dst, src); 1770 } else if (source->IsStackSlot()) { 1771 DCHECK(destination->IsRegister() || destination->IsStackSlot()); 1772 Operand src = g.ToOperand(source); 1773 if (destination->IsRegister()) { 1774 Register dst = g.ToRegister(destination); 1775 __ mov(dst, src); 1776 } else { 1777 Operand dst = g.ToOperand(destination); 1778 __ push(src); 1779 __ pop(dst); 1780 } 1781 } else if (source->IsConstant()) { 1782 Constant src_constant = g.ToConstant(source); 1783 if (src_constant.type() == Constant::kHeapObject) { 1784 Handle<HeapObject> src = src_constant.ToHeapObject(); 1785 int slot; 1786 if (IsMaterializableFromFrame(src, &slot)) { 1787 if (destination->IsRegister()) { 1788 Register dst = g.ToRegister(destination); 1789 __ mov(dst, g.SlotToOperand(slot)); 1790 } else { 1791 DCHECK(destination->IsStackSlot()); 1792 Operand dst = g.ToOperand(destination); 1793 __ push(g.SlotToOperand(slot)); 1794 __ pop(dst); 1795 } 1796 } else if (destination->IsRegister()) { 1797 Register dst = g.ToRegister(destination); 1798 __ LoadHeapObject(dst, src); 1799 } else { 1800 DCHECK(destination->IsStackSlot()); 1801 Operand dst = g.ToOperand(destination); 1802 AllowDeferredHandleDereference embedding_raw_address; 1803 if (isolate()->heap()->InNewSpace(*src)) { 1804 __ PushHeapObject(src); 1805 __ pop(dst); 1806 } else { 1807 __ mov(dst, src); 1808 } 1809 } 1810 } else if (destination->IsRegister()) { 1811 Register dst = g.ToRegister(destination); 1812 __ Move(dst, g.ToImmediate(source)); 1813 } else if (destination->IsStackSlot()) { 1814 Operand dst = g.ToOperand(destination); 1815 __ Move(dst, g.ToImmediate(source)); 1816 } else if (src_constant.type() == Constant::kFloat32) { 1817 // TODO(turbofan): Can we do better here? 1818 uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32()); 1819 if (destination->IsFPRegister()) { 1820 XMMRegister dst = g.ToDoubleRegister(destination); 1821 __ Move(dst, src); 1822 } else { 1823 DCHECK(destination->IsFPStackSlot()); 1824 Operand dst = g.ToOperand(destination); 1825 __ Move(dst, Immediate(src)); 1826 } 1827 } else { 1828 DCHECK_EQ(Constant::kFloat64, src_constant.type()); 1829 uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64()); 1830 uint32_t lower = static_cast<uint32_t>(src); 1831 uint32_t upper = static_cast<uint32_t>(src >> 32); 1832 if (destination->IsFPRegister()) { 1833 XMMRegister dst = g.ToDoubleRegister(destination); 1834 __ Move(dst, src); 1835 } else { 1836 DCHECK(destination->IsFPStackSlot()); 1837 Operand dst0 = g.ToOperand(destination); 1838 Operand dst1 = g.HighOperand(destination); 1839 __ Move(dst0, Immediate(lower)); 1840 __ Move(dst1, Immediate(upper)); 1841 } 1842 } 1843 } else if (source->IsFPRegister()) { 1844 XMMRegister src = g.ToDoubleRegister(source); 1845 if (destination->IsFPRegister()) { 1846 XMMRegister dst = g.ToDoubleRegister(destination); 1847 __ movaps(dst, src); 1848 } else { 1849 DCHECK(destination->IsFPStackSlot()); 1850 Operand dst = g.ToOperand(destination); 1851 __ movsd(dst, src); 1852 } 1853 } else if (source->IsFPStackSlot()) { 1854 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); 1855 Operand src = g.ToOperand(source); 1856 if (destination->IsFPRegister()) { 1857 XMMRegister dst = g.ToDoubleRegister(destination); 1858 __ movsd(dst, src); 1859 } else { 1860 Operand dst = g.ToOperand(destination); 1861 __ movsd(kScratchDoubleReg, src); 1862 __ movsd(dst, kScratchDoubleReg); 1863 } 1864 } else { 1865 UNREACHABLE(); 1866 } 1867} 1868 1869 1870void CodeGenerator::AssembleSwap(InstructionOperand* source, 1871 InstructionOperand* destination) { 1872 IA32OperandConverter g(this, nullptr); 1873 // Dispatch on the source and destination operand kinds. Not all 1874 // combinations are possible. 1875 if (source->IsRegister() && destination->IsRegister()) { 1876 // Register-register. 1877 Register src = g.ToRegister(source); 1878 Register dst = g.ToRegister(destination); 1879 __ push(src); 1880 __ mov(src, dst); 1881 __ pop(dst); 1882 } else if (source->IsRegister() && destination->IsStackSlot()) { 1883 // Register-memory. 1884 Register src = g.ToRegister(source); 1885 __ push(src); 1886 frame_access_state()->IncreaseSPDelta(1); 1887 Operand dst = g.ToOperand(destination); 1888 __ mov(src, dst); 1889 frame_access_state()->IncreaseSPDelta(-1); 1890 dst = g.ToOperand(destination); 1891 __ pop(dst); 1892 } else if (source->IsStackSlot() && destination->IsStackSlot()) { 1893 // Memory-memory. 1894 Operand dst1 = g.ToOperand(destination); 1895 __ push(dst1); 1896 frame_access_state()->IncreaseSPDelta(1); 1897 Operand src1 = g.ToOperand(source); 1898 __ push(src1); 1899 Operand dst2 = g.ToOperand(destination); 1900 __ pop(dst2); 1901 frame_access_state()->IncreaseSPDelta(-1); 1902 Operand src2 = g.ToOperand(source); 1903 __ pop(src2); 1904 } else if (source->IsFPRegister() && destination->IsFPRegister()) { 1905 // XMM register-register swap. 1906 XMMRegister src = g.ToDoubleRegister(source); 1907 XMMRegister dst = g.ToDoubleRegister(destination); 1908 __ movaps(kScratchDoubleReg, src); 1909 __ movaps(src, dst); 1910 __ movaps(dst, kScratchDoubleReg); 1911 } else if (source->IsFPRegister() && destination->IsFPStackSlot()) { 1912 // XMM register-memory swap. 1913 XMMRegister reg = g.ToDoubleRegister(source); 1914 Operand other = g.ToOperand(destination); 1915 __ movsd(kScratchDoubleReg, other); 1916 __ movsd(other, reg); 1917 __ movaps(reg, kScratchDoubleReg); 1918 } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) { 1919 // Double-width memory-to-memory. 1920 Operand src0 = g.ToOperand(source); 1921 Operand src1 = g.HighOperand(source); 1922 Operand dst0 = g.ToOperand(destination); 1923 Operand dst1 = g.HighOperand(destination); 1924 __ movsd(kScratchDoubleReg, dst0); // Save destination in scratch register. 1925 __ push(src0); // Then use stack to copy source to destination. 1926 __ pop(dst0); 1927 __ push(src1); 1928 __ pop(dst1); 1929 __ movsd(src0, kScratchDoubleReg); 1930 } else { 1931 // No other combinations are possible. 1932 UNREACHABLE(); 1933 } 1934} 1935 1936 1937void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { 1938 for (size_t index = 0; index < target_count; ++index) { 1939 __ dd(targets[index]); 1940 } 1941} 1942 1943 1944void CodeGenerator::EnsureSpaceForLazyDeopt() { 1945 if (!info()->ShouldEnsureSpaceForLazyDeopt()) { 1946 return; 1947 } 1948 1949 int space_needed = Deoptimizer::patch_size(); 1950 // Ensure that we have enough space after the previous lazy-bailout 1951 // instruction for patching the code here. 1952 int current_pc = masm()->pc_offset(); 1953 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 1954 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 1955 __ Nop(padding_size); 1956 } 1957} 1958 1959#undef __ 1960 1961} // namespace compiler 1962} // namespace internal 1963} // namespace v8 1964