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