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