code_generator_x86.cc revision b2bd1c5f9171f35fa5b71ada42d1a9e11189428d
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "code_generator_x86.h" 18 19#include "entrypoints/quick/quick_entrypoints.h" 20#include "entrypoints/quick/quick_entrypoints_enum.h" 21#include "gc/accounting/card_table.h" 22#include "mirror/array-inl.h" 23#include "mirror/art_method.h" 24#include "mirror/class.h" 25#include "thread.h" 26#include "utils/assembler.h" 27#include "utils/stack_checks.h" 28#include "utils/x86/assembler_x86.h" 29#include "utils/x86/managed_register_x86.h" 30 31namespace art { 32 33namespace x86 { 34 35static constexpr int kCurrentMethodStackOffset = 0; 36 37static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX }; 38static constexpr size_t kRuntimeParameterCoreRegistersLength = 39 arraysize(kRuntimeParameterCoreRegisters); 40static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI }; 41static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 }; 42static constexpr size_t kRuntimeParameterFpuRegistersLength = 43 arraysize(kRuntimeParameterFpuRegisters); 44 45static constexpr int kC2ConditionMask = 0x400; 46 47static constexpr int kFakeReturnRegister = Register(8); 48 49class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> { 50 public: 51 InvokeRuntimeCallingConvention() 52 : CallingConvention(kRuntimeParameterCoreRegisters, 53 kRuntimeParameterCoreRegistersLength, 54 kRuntimeParameterFpuRegisters, 55 kRuntimeParameterFpuRegistersLength) {} 56 57 private: 58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 59}; 60 61#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())-> 62 63class SlowPathCodeX86 : public SlowPathCode { 64 public: 65 SlowPathCodeX86() : entry_label_(), exit_label_() {} 66 67 Label* GetEntryLabel() { return &entry_label_; } 68 Label* GetExitLabel() { return &exit_label_; } 69 70 private: 71 Label entry_label_; 72 Label exit_label_; 73 74 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86); 75}; 76 77class NullCheckSlowPathX86 : public SlowPathCodeX86 { 78 public: 79 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {} 80 81 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 82 __ Bind(GetEntryLabel()); 83 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer))); 84 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 85 } 86 87 private: 88 HNullCheck* const instruction_; 89 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86); 90}; 91 92class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 { 93 public: 94 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {} 95 96 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 97 __ Bind(GetEntryLabel()); 98 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero))); 99 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 100 } 101 102 private: 103 HDivZeroCheck* const instruction_; 104 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86); 105}; 106 107class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 { 108 public: 109 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {} 110 111 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 112 __ Bind(GetEntryLabel()); 113 if (is_div_) { 114 __ negl(reg_); 115 } else { 116 __ movl(reg_, Immediate(0)); 117 } 118 __ jmp(GetExitLabel()); 119 } 120 121 private: 122 Register reg_; 123 bool is_div_; 124 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86); 125}; 126 127class BoundsCheckSlowPathX86 : public SlowPathCodeX86 { 128 public: 129 BoundsCheckSlowPathX86(HBoundsCheck* instruction, 130 Location index_location, 131 Location length_location) 132 : instruction_(instruction), 133 index_location_(index_location), 134 length_location_(length_location) {} 135 136 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 137 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 138 __ Bind(GetEntryLabel()); 139 // We're moving two locations to locations that could overlap, so we need a parallel 140 // move resolver. 141 InvokeRuntimeCallingConvention calling_convention; 142 x86_codegen->EmitParallelMoves( 143 index_location_, 144 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 145 length_location_, 146 Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 147 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds))); 148 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 149 } 150 151 private: 152 HBoundsCheck* const instruction_; 153 const Location index_location_; 154 const Location length_location_; 155 156 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86); 157}; 158 159class SuspendCheckSlowPathX86 : public SlowPathCodeX86 { 160 public: 161 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor) 162 : instruction_(instruction), successor_(successor) {} 163 164 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 165 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 166 __ Bind(GetEntryLabel()); 167 SaveLiveRegisters(codegen, instruction_->GetLocations()); 168 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend))); 169 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 170 RestoreLiveRegisters(codegen, instruction_->GetLocations()); 171 if (successor_ == nullptr) { 172 __ jmp(GetReturnLabel()); 173 } else { 174 __ jmp(x86_codegen->GetLabelOf(successor_)); 175 } 176 } 177 178 Label* GetReturnLabel() { 179 DCHECK(successor_ == nullptr); 180 return &return_label_; 181 } 182 183 private: 184 HSuspendCheck* const instruction_; 185 HBasicBlock* const successor_; 186 Label return_label_; 187 188 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86); 189}; 190 191class LoadStringSlowPathX86 : public SlowPathCodeX86 { 192 public: 193 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {} 194 195 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 196 LocationSummary* locations = instruction_->GetLocations(); 197 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 198 199 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 200 __ Bind(GetEntryLabel()); 201 SaveLiveRegisters(codegen, locations); 202 203 InvokeRuntimeCallingConvention calling_convention; 204 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 205 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex())); 206 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString))); 207 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc()); 208 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); 209 RestoreLiveRegisters(codegen, locations); 210 211 __ jmp(GetExitLabel()); 212 } 213 214 private: 215 HLoadString* const instruction_; 216 217 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86); 218}; 219 220class LoadClassSlowPathX86 : public SlowPathCodeX86 { 221 public: 222 LoadClassSlowPathX86(HLoadClass* cls, 223 HInstruction* at, 224 uint32_t dex_pc, 225 bool do_clinit) 226 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { 227 DCHECK(at->IsLoadClass() || at->IsClinitCheck()); 228 } 229 230 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 231 LocationSummary* locations = at_->GetLocations(); 232 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 233 __ Bind(GetEntryLabel()); 234 SaveLiveRegisters(codegen, locations); 235 236 InvokeRuntimeCallingConvention calling_convention; 237 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex())); 238 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 239 __ fs()->call(Address::Absolute(do_clinit_ 240 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage) 241 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType))); 242 RecordPcInfo(codegen, at_, dex_pc_); 243 244 // Move the class to the desired location. 245 Location out = locations->Out(); 246 if (out.IsValid()) { 247 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 248 x86_codegen->Move32(out, Location::RegisterLocation(EAX)); 249 } 250 251 RestoreLiveRegisters(codegen, locations); 252 __ jmp(GetExitLabel()); 253 } 254 255 private: 256 // The class this slow path will load. 257 HLoadClass* const cls_; 258 259 // The instruction where this slow path is happening. 260 // (Might be the load class or an initialization check). 261 HInstruction* const at_; 262 263 // The dex PC of `at_`. 264 const uint32_t dex_pc_; 265 266 // Whether to initialize the class. 267 const bool do_clinit_; 268 269 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86); 270}; 271 272class TypeCheckSlowPathX86 : public SlowPathCodeX86 { 273 public: 274 TypeCheckSlowPathX86(HInstruction* instruction, 275 Location class_to_check, 276 Location object_class, 277 uint32_t dex_pc) 278 : instruction_(instruction), 279 class_to_check_(class_to_check), 280 object_class_(object_class), 281 dex_pc_(dex_pc) {} 282 283 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 284 LocationSummary* locations = instruction_->GetLocations(); 285 DCHECK(instruction_->IsCheckCast() 286 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 287 288 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 289 __ Bind(GetEntryLabel()); 290 SaveLiveRegisters(codegen, locations); 291 292 // We're moving two locations to locations that could overlap, so we need a parallel 293 // move resolver. 294 InvokeRuntimeCallingConvention calling_convention; 295 x86_codegen->EmitParallelMoves( 296 class_to_check_, 297 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 298 object_class_, 299 Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 300 301 if (instruction_->IsInstanceOf()) { 302 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, 303 pInstanceofNonTrivial))); 304 } else { 305 DCHECK(instruction_->IsCheckCast()); 306 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast))); 307 } 308 309 RecordPcInfo(codegen, instruction_, dex_pc_); 310 if (instruction_->IsInstanceOf()) { 311 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); 312 } 313 RestoreLiveRegisters(codegen, locations); 314 315 __ jmp(GetExitLabel()); 316 } 317 318 private: 319 HInstruction* const instruction_; 320 const Location class_to_check_; 321 const Location object_class_; 322 const uint32_t dex_pc_; 323 324 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86); 325}; 326 327#undef __ 328#define __ reinterpret_cast<X86Assembler*>(GetAssembler())-> 329 330inline Condition X86Condition(IfCondition cond) { 331 switch (cond) { 332 case kCondEQ: return kEqual; 333 case kCondNE: return kNotEqual; 334 case kCondLT: return kLess; 335 case kCondLE: return kLessEqual; 336 case kCondGT: return kGreater; 337 case kCondGE: return kGreaterEqual; 338 default: 339 LOG(FATAL) << "Unknown if condition"; 340 } 341 return kEqual; 342} 343 344void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const { 345 stream << X86ManagedRegister::FromCpuRegister(Register(reg)); 346} 347 348void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 349 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg)); 350} 351 352size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { 353 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id)); 354 return kX86WordSize; 355} 356 357size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { 358 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index)); 359 return kX86WordSize; 360} 361 362size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 363 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id)); 364 return GetFloatingPointSpillSlotSize(); 365} 366 367size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 368 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index)); 369 return GetFloatingPointSpillSlotSize(); 370} 371 372CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options) 373 : CodeGenerator(graph, 374 kNumberOfCpuRegisters, 375 kNumberOfXmmRegisters, 376 kNumberOfRegisterPairs, 377 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves), 378 arraysize(kCoreCalleeSaves)) 379 | (1 << kFakeReturnRegister), 380 0, 381 compiler_options), 382 block_labels_(graph->GetArena(), 0), 383 location_builder_(graph, this), 384 instruction_visitor_(graph, this), 385 move_resolver_(graph->GetArena(), this) { 386 // Use a fake return address register to mimic Quick. 387 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister)); 388} 389 390Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const { 391 switch (type) { 392 case Primitive::kPrimLong: { 393 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs); 394 X86ManagedRegister pair = 395 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 396 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]); 397 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]); 398 blocked_core_registers_[pair.AsRegisterPairLow()] = true; 399 blocked_core_registers_[pair.AsRegisterPairHigh()] = true; 400 UpdateBlockedPairRegisters(); 401 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 402 } 403 404 case Primitive::kPrimByte: 405 case Primitive::kPrimBoolean: 406 case Primitive::kPrimChar: 407 case Primitive::kPrimShort: 408 case Primitive::kPrimInt: 409 case Primitive::kPrimNot: { 410 Register reg = static_cast<Register>( 411 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters)); 412 // Block all register pairs that contain `reg`. 413 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 414 X86ManagedRegister current = 415 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 416 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 417 blocked_register_pairs_[i] = true; 418 } 419 } 420 return Location::RegisterLocation(reg); 421 } 422 423 case Primitive::kPrimFloat: 424 case Primitive::kPrimDouble: { 425 return Location::FpuRegisterLocation( 426 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters)); 427 } 428 429 case Primitive::kPrimVoid: 430 LOG(FATAL) << "Unreachable type " << type; 431 } 432 433 return Location(); 434} 435 436void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const { 437 // Don't allocate the dalvik style register pair passing. 438 blocked_register_pairs_[ECX_EDX] = true; 439 440 // Stack register is always reserved. 441 blocked_core_registers_[ESP] = true; 442 443 if (is_baseline) { 444 blocked_core_registers_[EBP] = true; 445 blocked_core_registers_[ESI] = true; 446 blocked_core_registers_[EDI] = true; 447 } 448 449 UpdateBlockedPairRegisters(); 450} 451 452void CodeGeneratorX86::UpdateBlockedPairRegisters() const { 453 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 454 X86ManagedRegister current = 455 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 456 if (blocked_core_registers_[current.AsRegisterPairLow()] 457 || blocked_core_registers_[current.AsRegisterPairHigh()]) { 458 blocked_register_pairs_[i] = true; 459 } 460 } 461} 462 463InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen) 464 : HGraphVisitor(graph), 465 assembler_(codegen->GetAssembler()), 466 codegen_(codegen) {} 467 468void CodeGeneratorX86::GenerateFrameEntry() { 469 __ Bind(&frame_entry_label_); 470 bool skip_overflow_check = 471 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86); 472 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks()); 473 474 if (!skip_overflow_check) { 475 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86)))); 476 RecordPcInfo(nullptr, 0); 477 } 478 479 if (HasEmptyFrame()) { 480 return; 481 } 482 483 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) { 484 Register reg = kCoreCalleeSaves[i]; 485 if (allocated_registers_.ContainsCoreRegister(reg)) { 486 __ pushl(reg); 487 } 488 } 489 490 __ subl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize())); 491 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX); 492} 493 494void CodeGeneratorX86::GenerateFrameExit() { 495 if (HasEmptyFrame()) { 496 return; 497 } 498 499 __ addl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize())); 500 501 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) { 502 Register reg = kCoreCalleeSaves[i]; 503 if (allocated_registers_.ContainsCoreRegister(reg)) { 504 __ popl(reg); 505 } 506 } 507} 508 509void CodeGeneratorX86::Bind(HBasicBlock* block) { 510 __ Bind(GetLabelOf(block)); 511} 512 513void CodeGeneratorX86::LoadCurrentMethod(Register reg) { 514 DCHECK(RequiresCurrentMethod()); 515 __ movl(reg, Address(ESP, kCurrentMethodStackOffset)); 516} 517 518Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const { 519 switch (load->GetType()) { 520 case Primitive::kPrimLong: 521 case Primitive::kPrimDouble: 522 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 523 break; 524 525 case Primitive::kPrimInt: 526 case Primitive::kPrimNot: 527 case Primitive::kPrimFloat: 528 return Location::StackSlot(GetStackSlot(load->GetLocal())); 529 530 case Primitive::kPrimBoolean: 531 case Primitive::kPrimByte: 532 case Primitive::kPrimChar: 533 case Primitive::kPrimShort: 534 case Primitive::kPrimVoid: 535 LOG(FATAL) << "Unexpected type " << load->GetType(); 536 } 537 538 LOG(FATAL) << "Unreachable"; 539 return Location(); 540} 541 542Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 543 switch (type) { 544 case Primitive::kPrimBoolean: 545 case Primitive::kPrimByte: 546 case Primitive::kPrimChar: 547 case Primitive::kPrimShort: 548 case Primitive::kPrimInt: 549 case Primitive::kPrimNot: { 550 uint32_t index = gp_index_++; 551 stack_index_++; 552 if (index < calling_convention.GetNumberOfRegisters()) { 553 return Location::RegisterLocation(calling_convention.GetRegisterAt(index)); 554 } else { 555 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1)); 556 } 557 } 558 559 case Primitive::kPrimLong: { 560 uint32_t index = gp_index_; 561 gp_index_ += 2; 562 stack_index_ += 2; 563 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 564 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair( 565 calling_convention.GetRegisterPairAt(index)); 566 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 567 } else { 568 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2)); 569 } 570 } 571 572 case Primitive::kPrimFloat: { 573 uint32_t index = fp_index_++; 574 stack_index_++; 575 if (index < calling_convention.GetNumberOfFpuRegisters()) { 576 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index)); 577 } else { 578 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1)); 579 } 580 } 581 582 case Primitive::kPrimDouble: { 583 uint32_t index = fp_index_++; 584 stack_index_ += 2; 585 if (index < calling_convention.GetNumberOfFpuRegisters()) { 586 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index)); 587 } else { 588 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2)); 589 } 590 } 591 592 case Primitive::kPrimVoid: 593 LOG(FATAL) << "Unexpected parameter type " << type; 594 break; 595 } 596 return Location(); 597} 598 599void CodeGeneratorX86::Move32(Location destination, Location source) { 600 if (source.Equals(destination)) { 601 return; 602 } 603 if (destination.IsRegister()) { 604 if (source.IsRegister()) { 605 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 606 } else if (source.IsFpuRegister()) { 607 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>()); 608 } else { 609 DCHECK(source.IsStackSlot()); 610 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex())); 611 } 612 } else if (destination.IsFpuRegister()) { 613 if (source.IsRegister()) { 614 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>()); 615 } else if (source.IsFpuRegister()) { 616 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 617 } else { 618 DCHECK(source.IsStackSlot()); 619 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 620 } 621 } else { 622 DCHECK(destination.IsStackSlot()) << destination; 623 if (source.IsRegister()) { 624 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>()); 625 } else if (source.IsFpuRegister()) { 626 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 627 } else if (source.IsConstant()) { 628 HConstant* constant = source.GetConstant(); 629 int32_t value = GetInt32ValueOf(constant); 630 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value)); 631 } else { 632 DCHECK(source.IsStackSlot()); 633 __ pushl(Address(ESP, source.GetStackIndex())); 634 __ popl(Address(ESP, destination.GetStackIndex())); 635 } 636 } 637} 638 639void CodeGeneratorX86::Move64(Location destination, Location source) { 640 if (source.Equals(destination)) { 641 return; 642 } 643 if (destination.IsRegisterPair()) { 644 if (source.IsRegisterPair()) { 645 EmitParallelMoves( 646 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()), 647 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()), 648 Location::RegisterLocation(source.AsRegisterPairLow<Register>()), 649 Location::RegisterLocation(destination.AsRegisterPairLow<Register>())); 650 } else if (source.IsFpuRegister()) { 651 LOG(FATAL) << "Unimplemented"; 652 } else { 653 // No conflict possible, so just do the moves. 654 DCHECK(source.IsDoubleStackSlot()); 655 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex())); 656 __ movl(destination.AsRegisterPairHigh<Register>(), 657 Address(ESP, source.GetHighStackIndex(kX86WordSize))); 658 } 659 } else if (destination.IsFpuRegister()) { 660 if (source.IsFpuRegister()) { 661 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 662 } else if (source.IsDoubleStackSlot()) { 663 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 664 } else { 665 LOG(FATAL) << "Unimplemented"; 666 } 667 } else { 668 DCHECK(destination.IsDoubleStackSlot()) << destination; 669 if (source.IsRegisterPair()) { 670 // No conflict possible, so just do the moves. 671 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>()); 672 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), 673 source.AsRegisterPairHigh<Register>()); 674 } else if (source.IsFpuRegister()) { 675 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 676 } else if (source.IsConstant()) { 677 HConstant* constant = source.GetConstant(); 678 int64_t value; 679 if (constant->IsLongConstant()) { 680 value = constant->AsLongConstant()->GetValue(); 681 } else { 682 DCHECK(constant->IsDoubleConstant()); 683 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); 684 } 685 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value))); 686 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value))); 687 } else { 688 DCHECK(source.IsDoubleStackSlot()) << source; 689 EmitParallelMoves( 690 Location::StackSlot(source.GetStackIndex()), 691 Location::StackSlot(destination.GetStackIndex()), 692 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)), 693 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize))); 694 } 695 } 696} 697 698void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 699 LocationSummary* locations = instruction->GetLocations(); 700 if (locations != nullptr && locations->Out().Equals(location)) { 701 return; 702 } 703 704 if (locations != nullptr && locations->Out().IsConstant()) { 705 HConstant* const_to_move = locations->Out().GetConstant(); 706 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { 707 Immediate imm(GetInt32ValueOf(const_to_move)); 708 if (location.IsRegister()) { 709 __ movl(location.AsRegister<Register>(), imm); 710 } else if (location.IsStackSlot()) { 711 __ movl(Address(ESP, location.GetStackIndex()), imm); 712 } else { 713 DCHECK(location.IsConstant()); 714 DCHECK_EQ(location.GetConstant(), const_to_move); 715 } 716 } else if (const_to_move->IsLongConstant()) { 717 int64_t value = const_to_move->AsLongConstant()->GetValue(); 718 if (location.IsRegisterPair()) { 719 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 720 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 721 } else if (location.IsDoubleStackSlot()) { 722 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value))); 723 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), 724 Immediate(High32Bits(value))); 725 } else { 726 DCHECK(location.IsConstant()); 727 DCHECK_EQ(location.GetConstant(), instruction); 728 } 729 } 730 } else if (instruction->IsTemporary()) { 731 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 732 if (temp_location.IsStackSlot()) { 733 Move32(location, temp_location); 734 } else { 735 DCHECK(temp_location.IsDoubleStackSlot()); 736 Move64(location, temp_location); 737 } 738 } else if (instruction->IsLoadLocal()) { 739 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 740 switch (instruction->GetType()) { 741 case Primitive::kPrimBoolean: 742 case Primitive::kPrimByte: 743 case Primitive::kPrimChar: 744 case Primitive::kPrimShort: 745 case Primitive::kPrimInt: 746 case Primitive::kPrimNot: 747 case Primitive::kPrimFloat: 748 Move32(location, Location::StackSlot(slot)); 749 break; 750 751 case Primitive::kPrimLong: 752 case Primitive::kPrimDouble: 753 Move64(location, Location::DoubleStackSlot(slot)); 754 break; 755 756 default: 757 LOG(FATAL) << "Unimplemented local type " << instruction->GetType(); 758 } 759 } else { 760 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 761 switch (instruction->GetType()) { 762 case Primitive::kPrimBoolean: 763 case Primitive::kPrimByte: 764 case Primitive::kPrimChar: 765 case Primitive::kPrimShort: 766 case Primitive::kPrimInt: 767 case Primitive::kPrimNot: 768 case Primitive::kPrimFloat: 769 Move32(location, locations->Out()); 770 break; 771 772 case Primitive::kPrimLong: 773 case Primitive::kPrimDouble: 774 Move64(location, locations->Out()); 775 break; 776 777 default: 778 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 779 } 780 } 781} 782 783void LocationsBuilderX86::VisitGoto(HGoto* got) { 784 got->SetLocations(nullptr); 785} 786 787void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) { 788 HBasicBlock* successor = got->GetSuccessor(); 789 DCHECK(!successor->IsExitBlock()); 790 791 HBasicBlock* block = got->GetBlock(); 792 HInstruction* previous = got->GetPrevious(); 793 794 HLoopInformation* info = block->GetLoopInformation(); 795 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { 796 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 797 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 798 return; 799 } 800 801 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 802 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 803 } 804 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 805 __ jmp(codegen_->GetLabelOf(successor)); 806 } 807} 808 809void LocationsBuilderX86::VisitExit(HExit* exit) { 810 exit->SetLocations(nullptr); 811} 812 813void InstructionCodeGeneratorX86::VisitExit(HExit* exit) { 814 UNUSED(exit); 815} 816 817void LocationsBuilderX86::VisitIf(HIf* if_instr) { 818 LocationSummary* locations = 819 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 820 HInstruction* cond = if_instr->InputAt(0); 821 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 822 locations->SetInAt(0, Location::Any()); 823 } 824} 825 826void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { 827 HInstruction* cond = if_instr->InputAt(0); 828 if (cond->IsIntConstant()) { 829 // Constant condition, statically compared against 1. 830 int32_t cond_value = cond->AsIntConstant()->GetValue(); 831 if (cond_value == 1) { 832 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 833 if_instr->IfTrueSuccessor())) { 834 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 835 } 836 return; 837 } else { 838 DCHECK_EQ(cond_value, 0); 839 } 840 } else { 841 bool materialized = 842 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization(); 843 // Moves do not affect the eflags register, so if the condition is 844 // evaluated just before the if, we don't need to evaluate it 845 // again. 846 bool eflags_set = cond->IsCondition() 847 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr); 848 if (materialized) { 849 if (!eflags_set) { 850 // Materialized condition, compare against 0. 851 Location lhs = if_instr->GetLocations()->InAt(0); 852 if (lhs.IsRegister()) { 853 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 854 } else { 855 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0)); 856 } 857 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 858 } else { 859 __ j(X86Condition(cond->AsCondition()->GetCondition()), 860 codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 861 } 862 } else { 863 Location lhs = cond->GetLocations()->InAt(0); 864 Location rhs = cond->GetLocations()->InAt(1); 865 // LHS is guaranteed to be in a register (see 866 // LocationsBuilderX86::VisitCondition). 867 if (rhs.IsRegister()) { 868 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); 869 } else if (rhs.IsConstant()) { 870 int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue(); 871 if (constant == 0) { 872 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 873 } else { 874 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); 875 } 876 } else { 877 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); 878 } 879 __ j(X86Condition(cond->AsCondition()->GetCondition()), 880 codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 881 } 882 } 883 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 884 if_instr->IfFalseSuccessor())) { 885 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 886 } 887} 888 889void LocationsBuilderX86::VisitLocal(HLocal* local) { 890 local->SetLocations(nullptr); 891} 892 893void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) { 894 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 895} 896 897void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) { 898 local->SetLocations(nullptr); 899} 900 901void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) { 902 // Nothing to do, this is driven by the code generator. 903 UNUSED(load); 904} 905 906void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) { 907 LocationSummary* locations = 908 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 909 switch (store->InputAt(1)->GetType()) { 910 case Primitive::kPrimBoolean: 911 case Primitive::kPrimByte: 912 case Primitive::kPrimChar: 913 case Primitive::kPrimShort: 914 case Primitive::kPrimInt: 915 case Primitive::kPrimNot: 916 case Primitive::kPrimFloat: 917 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 918 break; 919 920 case Primitive::kPrimLong: 921 case Primitive::kPrimDouble: 922 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 923 break; 924 925 default: 926 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType(); 927 } 928 store->SetLocations(locations); 929} 930 931void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) { 932 UNUSED(store); 933} 934 935void LocationsBuilderX86::VisitCondition(HCondition* comp) { 936 LocationSummary* locations = 937 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 938 locations->SetInAt(0, Location::RequiresRegister()); 939 locations->SetInAt(1, Location::Any()); 940 if (comp->NeedsMaterialization()) { 941 // We need a byte register. 942 locations->SetOut(Location::RegisterLocation(ECX)); 943 } 944} 945 946void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) { 947 if (comp->NeedsMaterialization()) { 948 LocationSummary* locations = comp->GetLocations(); 949 Register reg = locations->Out().AsRegister<Register>(); 950 // Clear register: setcc only sets the low byte. 951 __ xorl(reg, reg); 952 Location lhs = locations->InAt(0); 953 Location rhs = locations->InAt(1); 954 if (rhs.IsRegister()) { 955 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); 956 } else if (rhs.IsConstant()) { 957 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()); 958 if (constant == 0) { 959 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 960 } else { 961 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); 962 } 963 } else { 964 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); 965 } 966 __ setb(X86Condition(comp->GetCondition()), reg); 967 } 968} 969 970void LocationsBuilderX86::VisitEqual(HEqual* comp) { 971 VisitCondition(comp); 972} 973 974void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) { 975 VisitCondition(comp); 976} 977 978void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) { 979 VisitCondition(comp); 980} 981 982void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) { 983 VisitCondition(comp); 984} 985 986void LocationsBuilderX86::VisitLessThan(HLessThan* comp) { 987 VisitCondition(comp); 988} 989 990void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) { 991 VisitCondition(comp); 992} 993 994void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 995 VisitCondition(comp); 996} 997 998void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 999 VisitCondition(comp); 1000} 1001 1002void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) { 1003 VisitCondition(comp); 1004} 1005 1006void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) { 1007 VisitCondition(comp); 1008} 1009 1010void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1011 VisitCondition(comp); 1012} 1013 1014void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1015 VisitCondition(comp); 1016} 1017 1018void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) { 1019 LocationSummary* locations = 1020 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1021 locations->SetOut(Location::ConstantLocation(constant)); 1022} 1023 1024void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) { 1025 // Will be generated at use site. 1026 UNUSED(constant); 1027} 1028 1029void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) { 1030 LocationSummary* locations = 1031 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1032 locations->SetOut(Location::ConstantLocation(constant)); 1033} 1034 1035void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) { 1036 // Will be generated at use site. 1037 UNUSED(constant); 1038} 1039 1040void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) { 1041 LocationSummary* locations = 1042 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1043 locations->SetOut(Location::ConstantLocation(constant)); 1044} 1045 1046void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) { 1047 // Will be generated at use site. 1048 UNUSED(constant); 1049} 1050 1051void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) { 1052 LocationSummary* locations = 1053 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1054 locations->SetOut(Location::ConstantLocation(constant)); 1055} 1056 1057void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) { 1058 // Will be generated at use site. 1059 UNUSED(constant); 1060} 1061 1062void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) { 1063 LocationSummary* locations = 1064 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1065 locations->SetOut(Location::ConstantLocation(constant)); 1066} 1067 1068void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) { 1069 // Will be generated at use site. 1070 UNUSED(constant); 1071} 1072 1073void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) { 1074 ret->SetLocations(nullptr); 1075} 1076 1077void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) { 1078 UNUSED(ret); 1079 codegen_->GenerateFrameExit(); 1080 __ ret(); 1081} 1082 1083void LocationsBuilderX86::VisitReturn(HReturn* ret) { 1084 LocationSummary* locations = 1085 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 1086 switch (ret->InputAt(0)->GetType()) { 1087 case Primitive::kPrimBoolean: 1088 case Primitive::kPrimByte: 1089 case Primitive::kPrimChar: 1090 case Primitive::kPrimShort: 1091 case Primitive::kPrimInt: 1092 case Primitive::kPrimNot: 1093 locations->SetInAt(0, Location::RegisterLocation(EAX)); 1094 break; 1095 1096 case Primitive::kPrimLong: 1097 locations->SetInAt( 1098 0, Location::RegisterPairLocation(EAX, EDX)); 1099 break; 1100 1101 case Primitive::kPrimFloat: 1102 case Primitive::kPrimDouble: 1103 locations->SetInAt( 1104 0, Location::FpuRegisterLocation(XMM0)); 1105 break; 1106 1107 default: 1108 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType(); 1109 } 1110} 1111 1112void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { 1113 if (kIsDebugBuild) { 1114 switch (ret->InputAt(0)->GetType()) { 1115 case Primitive::kPrimBoolean: 1116 case Primitive::kPrimByte: 1117 case Primitive::kPrimChar: 1118 case Primitive::kPrimShort: 1119 case Primitive::kPrimInt: 1120 case Primitive::kPrimNot: 1121 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX); 1122 break; 1123 1124 case Primitive::kPrimLong: 1125 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX); 1126 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX); 1127 break; 1128 1129 case Primitive::kPrimFloat: 1130 case Primitive::kPrimDouble: 1131 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0); 1132 break; 1133 1134 default: 1135 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType(); 1136 } 1137 } 1138 codegen_->GenerateFrameExit(); 1139 __ ret(); 1140} 1141 1142void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1143 HandleInvoke(invoke); 1144} 1145 1146void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1147 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1148 1149 // TODO: Implement all kinds of calls: 1150 // 1) boot -> boot 1151 // 2) app -> boot 1152 // 3) app -> app 1153 // 1154 // Currently we implement the app -> app logic, which looks up in the resolve cache. 1155 1156 // temp = method; 1157 codegen_->LoadCurrentMethod(temp); 1158 if (!invoke->IsRecursive()) { 1159 // temp = temp->dex_cache_resolved_methods_; 1160 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 1161 // temp = temp[index_in_cache] 1162 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()))); 1163 // (temp + offset_of_quick_compiled_code)() 1164 __ call(Address( 1165 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); 1166 } else { 1167 __ call(codegen_->GetFrameEntryLabel()); 1168 } 1169 1170 DCHECK(!codegen_->IsLeafMethod()); 1171 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1172} 1173 1174void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1175 HandleInvoke(invoke); 1176} 1177 1178void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) { 1179 LocationSummary* locations = 1180 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 1181 locations->AddTemp(Location::RegisterLocation(EAX)); 1182 1183 InvokeDexCallingConventionVisitor calling_convention_visitor; 1184 for (size_t i = 0; i < invoke->InputCount(); i++) { 1185 HInstruction* input = invoke->InputAt(i); 1186 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 1187 } 1188 1189 switch (invoke->GetType()) { 1190 case Primitive::kPrimBoolean: 1191 case Primitive::kPrimByte: 1192 case Primitive::kPrimChar: 1193 case Primitive::kPrimShort: 1194 case Primitive::kPrimInt: 1195 case Primitive::kPrimNot: 1196 locations->SetOut(Location::RegisterLocation(EAX)); 1197 break; 1198 1199 case Primitive::kPrimLong: 1200 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 1201 break; 1202 1203 case Primitive::kPrimVoid: 1204 break; 1205 1206 case Primitive::kPrimDouble: 1207 case Primitive::kPrimFloat: 1208 locations->SetOut(Location::FpuRegisterLocation(XMM0)); 1209 break; 1210 } 1211 1212 invoke->SetLocations(locations); 1213} 1214 1215void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1216 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1217 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 1218 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 1219 LocationSummary* locations = invoke->GetLocations(); 1220 Location receiver = locations->InAt(0); 1221 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1222 // temp = object->GetClass(); 1223 if (receiver.IsStackSlot()) { 1224 __ movl(temp, Address(ESP, receiver.GetStackIndex())); 1225 __ movl(temp, Address(temp, class_offset)); 1226 } else { 1227 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset)); 1228 } 1229 codegen_->MaybeRecordImplicitNullCheck(invoke); 1230 // temp = temp->GetMethodAt(method_offset); 1231 __ movl(temp, Address(temp, method_offset)); 1232 // call temp->GetEntryPoint(); 1233 __ call(Address( 1234 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); 1235 1236 DCHECK(!codegen_->IsLeafMethod()); 1237 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1238} 1239 1240void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { 1241 HandleInvoke(invoke); 1242 // Add the hidden argument. 1243 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7)); 1244} 1245 1246void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) { 1247 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1248 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1249 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 1250 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 1251 LocationSummary* locations = invoke->GetLocations(); 1252 Location receiver = locations->InAt(0); 1253 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1254 1255 // Set the hidden argument. 1256 __ movl(temp, Immediate(invoke->GetDexMethodIndex())); 1257 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp); 1258 1259 // temp = object->GetClass(); 1260 if (receiver.IsStackSlot()) { 1261 __ movl(temp, Address(ESP, receiver.GetStackIndex())); 1262 __ movl(temp, Address(temp, class_offset)); 1263 } else { 1264 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset)); 1265 } 1266 codegen_->MaybeRecordImplicitNullCheck(invoke); 1267 // temp = temp->GetImtEntryAt(method_offset); 1268 __ movl(temp, Address(temp, method_offset)); 1269 // call temp->GetEntryPoint(); 1270 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 1271 kX86WordSize).Int32Value())); 1272 1273 DCHECK(!codegen_->IsLeafMethod()); 1274 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1275} 1276 1277void LocationsBuilderX86::VisitNeg(HNeg* neg) { 1278 LocationSummary* locations = 1279 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 1280 switch (neg->GetResultType()) { 1281 case Primitive::kPrimInt: 1282 case Primitive::kPrimLong: 1283 locations->SetInAt(0, Location::RequiresRegister()); 1284 locations->SetOut(Location::SameAsFirstInput()); 1285 break; 1286 1287 case Primitive::kPrimFloat: 1288 locations->SetInAt(0, Location::RequiresFpuRegister()); 1289 locations->SetOut(Location::SameAsFirstInput()); 1290 locations->AddTemp(Location::RequiresRegister()); 1291 locations->AddTemp(Location::RequiresFpuRegister()); 1292 break; 1293 1294 case Primitive::kPrimDouble: 1295 locations->SetInAt(0, Location::RequiresFpuRegister()); 1296 locations->SetOut(Location::SameAsFirstInput()); 1297 locations->AddTemp(Location::RequiresFpuRegister()); 1298 break; 1299 1300 default: 1301 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1302 } 1303} 1304 1305void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { 1306 LocationSummary* locations = neg->GetLocations(); 1307 Location out = locations->Out(); 1308 Location in = locations->InAt(0); 1309 switch (neg->GetResultType()) { 1310 case Primitive::kPrimInt: 1311 DCHECK(in.IsRegister()); 1312 DCHECK(in.Equals(out)); 1313 __ negl(out.AsRegister<Register>()); 1314 break; 1315 1316 case Primitive::kPrimLong: 1317 DCHECK(in.IsRegisterPair()); 1318 DCHECK(in.Equals(out)); 1319 __ negl(out.AsRegisterPairLow<Register>()); 1320 // Negation is similar to subtraction from zero. The least 1321 // significant byte triggers a borrow when it is different from 1322 // zero; to take it into account, add 1 to the most significant 1323 // byte if the carry flag (CF) is set to 1 after the first NEGL 1324 // operation. 1325 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0)); 1326 __ negl(out.AsRegisterPairHigh<Register>()); 1327 break; 1328 1329 case Primitive::kPrimFloat: { 1330 DCHECK(in.Equals(out)); 1331 Register constant = locations->GetTemp(0).AsRegister<Register>(); 1332 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 1333 // Implement float negation with an exclusive or with value 1334 // 0x80000000 (mask for bit 31, representing the sign of a 1335 // single-precision floating-point number). 1336 __ movl(constant, Immediate(INT32_C(0x80000000))); 1337 __ movd(mask, constant); 1338 __ xorps(out.AsFpuRegister<XmmRegister>(), mask); 1339 break; 1340 } 1341 1342 case Primitive::kPrimDouble: { 1343 DCHECK(in.Equals(out)); 1344 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 1345 // Implement double negation with an exclusive or with value 1346 // 0x8000000000000000 (mask for bit 63, representing the sign of 1347 // a double-precision floating-point number). 1348 __ LoadLongConstant(mask, INT64_C(0x8000000000000000)); 1349 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask); 1350 break; 1351 } 1352 1353 default: 1354 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1355 } 1356} 1357 1358void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { 1359 Primitive::Type result_type = conversion->GetResultType(); 1360 Primitive::Type input_type = conversion->GetInputType(); 1361 DCHECK_NE(result_type, input_type); 1362 1363 // The float-to-long and double-to-long type conversions rely on a 1364 // call to the runtime. 1365 LocationSummary::CallKind call_kind = 1366 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) 1367 && result_type == Primitive::kPrimLong) 1368 ? LocationSummary::kCall 1369 : LocationSummary::kNoCall; 1370 LocationSummary* locations = 1371 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); 1372 1373 // The Java language does not allow treating boolean as an integral type but 1374 // our bit representation makes it safe. 1375 1376 switch (result_type) { 1377 case Primitive::kPrimByte: 1378 switch (input_type) { 1379 case Primitive::kPrimBoolean: 1380 // Boolean input is a result of code transformations. 1381 case Primitive::kPrimShort: 1382 case Primitive::kPrimInt: 1383 case Primitive::kPrimChar: 1384 // Processing a Dex `int-to-byte' instruction. 1385 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0))); 1386 // Make the output overlap to please the register allocator. This greatly simplifies 1387 // the validation of the linear scan implementation 1388 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 1389 break; 1390 1391 default: 1392 LOG(FATAL) << "Unexpected type conversion from " << input_type 1393 << " to " << result_type; 1394 } 1395 break; 1396 1397 case Primitive::kPrimShort: 1398 switch (input_type) { 1399 case Primitive::kPrimBoolean: 1400 // Boolean input is a result of code transformations. 1401 case Primitive::kPrimByte: 1402 case Primitive::kPrimInt: 1403 case Primitive::kPrimChar: 1404 // Processing a Dex `int-to-short' instruction. 1405 locations->SetInAt(0, Location::Any()); 1406 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1407 break; 1408 1409 default: 1410 LOG(FATAL) << "Unexpected type conversion from " << input_type 1411 << " to " << result_type; 1412 } 1413 break; 1414 1415 case Primitive::kPrimInt: 1416 switch (input_type) { 1417 case Primitive::kPrimLong: 1418 // Processing a Dex `long-to-int' instruction. 1419 locations->SetInAt(0, Location::Any()); 1420 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1421 break; 1422 1423 case Primitive::kPrimFloat: 1424 // Processing a Dex `float-to-int' instruction. 1425 locations->SetInAt(0, Location::RequiresFpuRegister()); 1426 locations->SetOut(Location::RequiresRegister()); 1427 locations->AddTemp(Location::RequiresFpuRegister()); 1428 break; 1429 1430 case Primitive::kPrimDouble: 1431 // Processing a Dex `double-to-int' instruction. 1432 locations->SetInAt(0, Location::RequiresFpuRegister()); 1433 locations->SetOut(Location::RequiresRegister()); 1434 locations->AddTemp(Location::RequiresFpuRegister()); 1435 break; 1436 1437 default: 1438 LOG(FATAL) << "Unexpected type conversion from " << input_type 1439 << " to " << result_type; 1440 } 1441 break; 1442 1443 case Primitive::kPrimLong: 1444 switch (input_type) { 1445 case Primitive::kPrimBoolean: 1446 // Boolean input is a result of code transformations. 1447 case Primitive::kPrimByte: 1448 case Primitive::kPrimShort: 1449 case Primitive::kPrimInt: 1450 case Primitive::kPrimChar: 1451 // Processing a Dex `int-to-long' instruction. 1452 locations->SetInAt(0, Location::RegisterLocation(EAX)); 1453 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 1454 break; 1455 1456 case Primitive::kPrimFloat: 1457 case Primitive::kPrimDouble: { 1458 // Processing a Dex `float-to-long' or 'double-to-long' instruction. 1459 InvokeRuntimeCallingConvention calling_convention; 1460 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0); 1461 locations->SetInAt(0, Location::FpuRegisterLocation(parameter)); 1462 1463 // The runtime helper puts the result in EAX, EDX. 1464 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 1465 } 1466 break; 1467 1468 default: 1469 LOG(FATAL) << "Unexpected type conversion from " << input_type 1470 << " to " << result_type; 1471 } 1472 break; 1473 1474 case Primitive::kPrimChar: 1475 switch (input_type) { 1476 case Primitive::kPrimBoolean: 1477 // Boolean input is a result of code transformations. 1478 case Primitive::kPrimByte: 1479 case Primitive::kPrimShort: 1480 case Primitive::kPrimInt: 1481 // Processing a Dex `int-to-char' instruction. 1482 locations->SetInAt(0, Location::Any()); 1483 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1484 break; 1485 1486 default: 1487 LOG(FATAL) << "Unexpected type conversion from " << input_type 1488 << " to " << result_type; 1489 } 1490 break; 1491 1492 case Primitive::kPrimFloat: 1493 switch (input_type) { 1494 case Primitive::kPrimBoolean: 1495 // Boolean input is a result of code transformations. 1496 case Primitive::kPrimByte: 1497 case Primitive::kPrimShort: 1498 case Primitive::kPrimInt: 1499 case Primitive::kPrimChar: 1500 // Processing a Dex `int-to-float' instruction. 1501 locations->SetInAt(0, Location::RequiresRegister()); 1502 locations->SetOut(Location::RequiresFpuRegister()); 1503 break; 1504 1505 case Primitive::kPrimLong: 1506 // Processing a Dex `long-to-float' instruction. 1507 locations->SetInAt(0, Location::RequiresRegister()); 1508 locations->SetOut(Location::RequiresFpuRegister()); 1509 locations->AddTemp(Location::RequiresFpuRegister()); 1510 locations->AddTemp(Location::RequiresFpuRegister()); 1511 break; 1512 1513 case Primitive::kPrimDouble: 1514 // Processing a Dex `double-to-float' instruction. 1515 locations->SetInAt(0, Location::RequiresFpuRegister()); 1516 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1517 break; 1518 1519 default: 1520 LOG(FATAL) << "Unexpected type conversion from " << input_type 1521 << " to " << result_type; 1522 }; 1523 break; 1524 1525 case Primitive::kPrimDouble: 1526 switch (input_type) { 1527 case Primitive::kPrimBoolean: 1528 // Boolean input is a result of code transformations. 1529 case Primitive::kPrimByte: 1530 case Primitive::kPrimShort: 1531 case Primitive::kPrimInt: 1532 case Primitive::kPrimChar: 1533 // Processing a Dex `int-to-double' instruction. 1534 locations->SetInAt(0, Location::RequiresRegister()); 1535 locations->SetOut(Location::RequiresFpuRegister()); 1536 break; 1537 1538 case Primitive::kPrimLong: 1539 // Processing a Dex `long-to-double' instruction. 1540 locations->SetInAt(0, Location::RequiresRegister()); 1541 locations->SetOut(Location::RequiresFpuRegister()); 1542 locations->AddTemp(Location::RequiresFpuRegister()); 1543 locations->AddTemp(Location::RequiresFpuRegister()); 1544 break; 1545 1546 case Primitive::kPrimFloat: 1547 // Processing a Dex `float-to-double' instruction. 1548 locations->SetInAt(0, Location::RequiresFpuRegister()); 1549 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1550 break; 1551 1552 default: 1553 LOG(FATAL) << "Unexpected type conversion from " << input_type 1554 << " to " << result_type; 1555 } 1556 break; 1557 1558 default: 1559 LOG(FATAL) << "Unexpected type conversion from " << input_type 1560 << " to " << result_type; 1561 } 1562} 1563 1564void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) { 1565 LocationSummary* locations = conversion->GetLocations(); 1566 Location out = locations->Out(); 1567 Location in = locations->InAt(0); 1568 Primitive::Type result_type = conversion->GetResultType(); 1569 Primitive::Type input_type = conversion->GetInputType(); 1570 DCHECK_NE(result_type, input_type); 1571 switch (result_type) { 1572 case Primitive::kPrimByte: 1573 switch (input_type) { 1574 case Primitive::kPrimBoolean: 1575 // Boolean input is a result of code transformations. 1576 case Primitive::kPrimShort: 1577 case Primitive::kPrimInt: 1578 case Primitive::kPrimChar: 1579 // Processing a Dex `int-to-byte' instruction. 1580 if (in.IsRegister()) { 1581 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>()); 1582 } else { 1583 DCHECK(in.GetConstant()->IsIntConstant()); 1584 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 1585 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value))); 1586 } 1587 break; 1588 1589 default: 1590 LOG(FATAL) << "Unexpected type conversion from " << input_type 1591 << " to " << result_type; 1592 } 1593 break; 1594 1595 case Primitive::kPrimShort: 1596 switch (input_type) { 1597 case Primitive::kPrimBoolean: 1598 // Boolean input is a result of code transformations. 1599 case Primitive::kPrimByte: 1600 case Primitive::kPrimInt: 1601 case Primitive::kPrimChar: 1602 // Processing a Dex `int-to-short' instruction. 1603 if (in.IsRegister()) { 1604 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>()); 1605 } else if (in.IsStackSlot()) { 1606 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 1607 } else { 1608 DCHECK(in.GetConstant()->IsIntConstant()); 1609 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 1610 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value))); 1611 } 1612 break; 1613 1614 default: 1615 LOG(FATAL) << "Unexpected type conversion from " << input_type 1616 << " to " << result_type; 1617 } 1618 break; 1619 1620 case Primitive::kPrimInt: 1621 switch (input_type) { 1622 case Primitive::kPrimLong: 1623 // Processing a Dex `long-to-int' instruction. 1624 if (in.IsRegisterPair()) { 1625 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>()); 1626 } else if (in.IsDoubleStackSlot()) { 1627 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 1628 } else { 1629 DCHECK(in.IsConstant()); 1630 DCHECK(in.GetConstant()->IsLongConstant()); 1631 int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); 1632 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value))); 1633 } 1634 break; 1635 1636 case Primitive::kPrimFloat: { 1637 // Processing a Dex `float-to-int' instruction. 1638 XmmRegister input = in.AsFpuRegister<XmmRegister>(); 1639 Register output = out.AsRegister<Register>(); 1640 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 1641 Label done, nan; 1642 1643 __ movl(output, Immediate(kPrimIntMax)); 1644 // temp = int-to-float(output) 1645 __ cvtsi2ss(temp, output); 1646 // if input >= temp goto done 1647 __ comiss(input, temp); 1648 __ j(kAboveEqual, &done); 1649 // if input == NaN goto nan 1650 __ j(kUnordered, &nan); 1651 // output = float-to-int-truncate(input) 1652 __ cvttss2si(output, input); 1653 __ jmp(&done); 1654 __ Bind(&nan); 1655 // output = 0 1656 __ xorl(output, output); 1657 __ Bind(&done); 1658 break; 1659 } 1660 1661 case Primitive::kPrimDouble: { 1662 // Processing a Dex `double-to-int' instruction. 1663 XmmRegister input = in.AsFpuRegister<XmmRegister>(); 1664 Register output = out.AsRegister<Register>(); 1665 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 1666 Label done, nan; 1667 1668 __ movl(output, Immediate(kPrimIntMax)); 1669 // temp = int-to-double(output) 1670 __ cvtsi2sd(temp, output); 1671 // if input >= temp goto done 1672 __ comisd(input, temp); 1673 __ j(kAboveEqual, &done); 1674 // if input == NaN goto nan 1675 __ j(kUnordered, &nan); 1676 // output = double-to-int-truncate(input) 1677 __ cvttsd2si(output, input); 1678 __ jmp(&done); 1679 __ Bind(&nan); 1680 // output = 0 1681 __ xorl(output, output); 1682 __ Bind(&done); 1683 break; 1684 } 1685 1686 default: 1687 LOG(FATAL) << "Unexpected type conversion from " << input_type 1688 << " to " << result_type; 1689 } 1690 break; 1691 1692 case Primitive::kPrimLong: 1693 switch (input_type) { 1694 case Primitive::kPrimBoolean: 1695 // Boolean input is a result of code transformations. 1696 case Primitive::kPrimByte: 1697 case Primitive::kPrimShort: 1698 case Primitive::kPrimInt: 1699 case Primitive::kPrimChar: 1700 // Processing a Dex `int-to-long' instruction. 1701 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX); 1702 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX); 1703 DCHECK_EQ(in.AsRegister<Register>(), EAX); 1704 __ cdq(); 1705 break; 1706 1707 case Primitive::kPrimFloat: 1708 // Processing a Dex `float-to-long' instruction. 1709 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l))); 1710 codegen_->RecordPcInfo(conversion, conversion->GetDexPc()); 1711 break; 1712 1713 case Primitive::kPrimDouble: 1714 // Processing a Dex `double-to-long' instruction. 1715 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l))); 1716 codegen_->RecordPcInfo(conversion, conversion->GetDexPc()); 1717 break; 1718 1719 default: 1720 LOG(FATAL) << "Unexpected type conversion from " << input_type 1721 << " to " << result_type; 1722 } 1723 break; 1724 1725 case Primitive::kPrimChar: 1726 switch (input_type) { 1727 case Primitive::kPrimBoolean: 1728 // Boolean input is a result of code transformations. 1729 case Primitive::kPrimByte: 1730 case Primitive::kPrimShort: 1731 case Primitive::kPrimInt: 1732 // Processing a Dex `Process a Dex `int-to-char'' instruction. 1733 if (in.IsRegister()) { 1734 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>()); 1735 } else if (in.IsStackSlot()) { 1736 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 1737 } else { 1738 DCHECK(in.GetConstant()->IsIntConstant()); 1739 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 1740 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value))); 1741 } 1742 break; 1743 1744 default: 1745 LOG(FATAL) << "Unexpected type conversion from " << input_type 1746 << " to " << result_type; 1747 } 1748 break; 1749 1750 case Primitive::kPrimFloat: 1751 switch (input_type) { 1752 case Primitive::kPrimBoolean: 1753 // Boolean input is a result of code transformations. 1754 case Primitive::kPrimByte: 1755 case Primitive::kPrimShort: 1756 case Primitive::kPrimInt: 1757 case Primitive::kPrimChar: 1758 // Processing a Dex `int-to-float' instruction. 1759 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>()); 1760 break; 1761 1762 case Primitive::kPrimLong: { 1763 // Processing a Dex `long-to-float' instruction. 1764 Register low = in.AsRegisterPairLow<Register>(); 1765 Register high = in.AsRegisterPairHigh<Register>(); 1766 XmmRegister result = out.AsFpuRegister<XmmRegister>(); 1767 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 1768 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 1769 1770 // Operations use doubles for precision reasons (each 32-bit 1771 // half of a long fits in the 53-bit mantissa of a double, 1772 // but not in the 24-bit mantissa of a float). This is 1773 // especially important for the low bits. The result is 1774 // eventually converted to float. 1775 1776 // low = low - 2^31 (to prevent bit 31 of `low` to be 1777 // interpreted as a sign bit) 1778 __ subl(low, Immediate(0x80000000)); 1779 // temp = int-to-double(high) 1780 __ cvtsi2sd(temp, high); 1781 // temp = temp * 2^32 1782 __ LoadLongConstant(constant, k2Pow32EncodingForDouble); 1783 __ mulsd(temp, constant); 1784 // result = int-to-double(low) 1785 __ cvtsi2sd(result, low); 1786 // result = result + 2^31 (restore the original value of `low`) 1787 __ LoadLongConstant(constant, k2Pow31EncodingForDouble); 1788 __ addsd(result, constant); 1789 // result = result + temp 1790 __ addsd(result, temp); 1791 // result = double-to-float(result) 1792 __ cvtsd2ss(result, result); 1793 // Restore low. 1794 __ addl(low, Immediate(0x80000000)); 1795 break; 1796 } 1797 1798 case Primitive::kPrimDouble: 1799 // Processing a Dex `double-to-float' instruction. 1800 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>()); 1801 break; 1802 1803 default: 1804 LOG(FATAL) << "Unexpected type conversion from " << input_type 1805 << " to " << result_type; 1806 }; 1807 break; 1808 1809 case Primitive::kPrimDouble: 1810 switch (input_type) { 1811 case Primitive::kPrimBoolean: 1812 // Boolean input is a result of code transformations. 1813 case Primitive::kPrimByte: 1814 case Primitive::kPrimShort: 1815 case Primitive::kPrimInt: 1816 case Primitive::kPrimChar: 1817 // Processing a Dex `int-to-double' instruction. 1818 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>()); 1819 break; 1820 1821 case Primitive::kPrimLong: { 1822 // Processing a Dex `long-to-double' instruction. 1823 Register low = in.AsRegisterPairLow<Register>(); 1824 Register high = in.AsRegisterPairHigh<Register>(); 1825 XmmRegister result = out.AsFpuRegister<XmmRegister>(); 1826 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 1827 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 1828 1829 // low = low - 2^31 (to prevent bit 31 of `low` to be 1830 // interpreted as a sign bit) 1831 __ subl(low, Immediate(0x80000000)); 1832 // temp = int-to-double(high) 1833 __ cvtsi2sd(temp, high); 1834 // temp = temp * 2^32 1835 __ LoadLongConstant(constant, k2Pow32EncodingForDouble); 1836 __ mulsd(temp, constant); 1837 // result = int-to-double(low) 1838 __ cvtsi2sd(result, low); 1839 // result = result + 2^31 (restore the original value of `low`) 1840 __ LoadLongConstant(constant, k2Pow31EncodingForDouble); 1841 __ addsd(result, constant); 1842 // result = result + temp 1843 __ addsd(result, temp); 1844 // Restore low. 1845 __ addl(low, Immediate(0x80000000)); 1846 break; 1847 } 1848 1849 case Primitive::kPrimFloat: 1850 // Processing a Dex `float-to-double' instruction. 1851 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>()); 1852 break; 1853 1854 default: 1855 LOG(FATAL) << "Unexpected type conversion from " << input_type 1856 << " to " << result_type; 1857 }; 1858 break; 1859 1860 default: 1861 LOG(FATAL) << "Unexpected type conversion from " << input_type 1862 << " to " << result_type; 1863 } 1864} 1865 1866void LocationsBuilderX86::VisitAdd(HAdd* add) { 1867 LocationSummary* locations = 1868 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1869 switch (add->GetResultType()) { 1870 case Primitive::kPrimInt: { 1871 locations->SetInAt(0, Location::RequiresRegister()); 1872 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 1873 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1874 break; 1875 } 1876 1877 case Primitive::kPrimLong: { 1878 locations->SetInAt(0, Location::RequiresRegister()); 1879 locations->SetInAt(1, Location::Any()); 1880 locations->SetOut(Location::SameAsFirstInput()); 1881 break; 1882 } 1883 1884 case Primitive::kPrimFloat: 1885 case Primitive::kPrimDouble: { 1886 locations->SetInAt(0, Location::RequiresFpuRegister()); 1887 locations->SetInAt(1, Location::RequiresFpuRegister()); 1888 locations->SetOut(Location::SameAsFirstInput()); 1889 break; 1890 } 1891 1892 default: 1893 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1894 break; 1895 } 1896} 1897 1898void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { 1899 LocationSummary* locations = add->GetLocations(); 1900 Location first = locations->InAt(0); 1901 Location second = locations->InAt(1); 1902 Location out = locations->Out(); 1903 1904 switch (add->GetResultType()) { 1905 case Primitive::kPrimInt: { 1906 if (second.IsRegister()) { 1907 if (out.AsRegister<Register>() == first.AsRegister<Register>()) { 1908 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>()); 1909 } else { 1910 __ leal(out.AsRegister<Register>(), Address( 1911 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0)); 1912 } 1913 } else if (second.IsConstant()) { 1914 int32_t value = second.GetConstant()->AsIntConstant()->GetValue(); 1915 if (out.AsRegister<Register>() == first.AsRegister<Register>()) { 1916 __ addl(out.AsRegister<Register>(), Immediate(value)); 1917 } else { 1918 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value)); 1919 } 1920 } else { 1921 DCHECK(first.Equals(locations->Out())); 1922 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 1923 } 1924 break; 1925 } 1926 1927 case Primitive::kPrimLong: { 1928 if (second.IsRegisterPair()) { 1929 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 1930 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 1931 } else if (second.IsDoubleStackSlot()) { 1932 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 1933 __ adcl(first.AsRegisterPairHigh<Register>(), 1934 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 1935 } else { 1936 DCHECK(second.IsConstant()) << second; 1937 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 1938 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 1939 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 1940 } 1941 break; 1942 } 1943 1944 case Primitive::kPrimFloat: { 1945 if (second.IsFpuRegister()) { 1946 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 1947 } 1948 break; 1949 } 1950 1951 case Primitive::kPrimDouble: { 1952 if (second.IsFpuRegister()) { 1953 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 1954 } 1955 break; 1956 } 1957 1958 default: 1959 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1960 } 1961} 1962 1963void LocationsBuilderX86::VisitSub(HSub* sub) { 1964 LocationSummary* locations = 1965 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1966 switch (sub->GetResultType()) { 1967 case Primitive::kPrimInt: 1968 case Primitive::kPrimLong: { 1969 locations->SetInAt(0, Location::RequiresRegister()); 1970 locations->SetInAt(1, Location::Any()); 1971 locations->SetOut(Location::SameAsFirstInput()); 1972 break; 1973 } 1974 case Primitive::kPrimFloat: 1975 case Primitive::kPrimDouble: { 1976 locations->SetInAt(0, Location::RequiresFpuRegister()); 1977 locations->SetInAt(1, Location::RequiresFpuRegister()); 1978 locations->SetOut(Location::SameAsFirstInput()); 1979 break; 1980 } 1981 1982 default: 1983 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1984 } 1985} 1986 1987void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { 1988 LocationSummary* locations = sub->GetLocations(); 1989 Location first = locations->InAt(0); 1990 Location second = locations->InAt(1); 1991 DCHECK(first.Equals(locations->Out())); 1992 switch (sub->GetResultType()) { 1993 case Primitive::kPrimInt: { 1994 if (second.IsRegister()) { 1995 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>()); 1996 } else if (second.IsConstant()) { 1997 __ subl(first.AsRegister<Register>(), 1998 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 1999 } else { 2000 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 2001 } 2002 break; 2003 } 2004 2005 case Primitive::kPrimLong: { 2006 if (second.IsRegisterPair()) { 2007 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 2008 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 2009 } else if (second.IsDoubleStackSlot()) { 2010 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 2011 __ sbbl(first.AsRegisterPairHigh<Register>(), 2012 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 2013 } else { 2014 DCHECK(second.IsConstant()) << second; 2015 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 2016 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 2017 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 2018 } 2019 break; 2020 } 2021 2022 case Primitive::kPrimFloat: { 2023 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2024 break; 2025 } 2026 2027 case Primitive::kPrimDouble: { 2028 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2029 break; 2030 } 2031 2032 default: 2033 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 2034 } 2035} 2036 2037void LocationsBuilderX86::VisitMul(HMul* mul) { 2038 LocationSummary* locations = 2039 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 2040 switch (mul->GetResultType()) { 2041 case Primitive::kPrimInt: 2042 locations->SetInAt(0, Location::RequiresRegister()); 2043 locations->SetInAt(1, Location::Any()); 2044 locations->SetOut(Location::SameAsFirstInput()); 2045 break; 2046 case Primitive::kPrimLong: { 2047 locations->SetInAt(0, Location::RequiresRegister()); 2048 locations->SetInAt(1, Location::Any()); 2049 locations->SetOut(Location::SameAsFirstInput()); 2050 // Needed for imul on 32bits with 64bits output. 2051 locations->AddTemp(Location::RegisterLocation(EAX)); 2052 locations->AddTemp(Location::RegisterLocation(EDX)); 2053 break; 2054 } 2055 case Primitive::kPrimFloat: 2056 case Primitive::kPrimDouble: { 2057 locations->SetInAt(0, Location::RequiresFpuRegister()); 2058 locations->SetInAt(1, Location::RequiresFpuRegister()); 2059 locations->SetOut(Location::SameAsFirstInput()); 2060 break; 2061 } 2062 2063 default: 2064 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 2065 } 2066} 2067 2068void InstructionCodeGeneratorX86::VisitMul(HMul* mul) { 2069 LocationSummary* locations = mul->GetLocations(); 2070 Location first = locations->InAt(0); 2071 Location second = locations->InAt(1); 2072 DCHECK(first.Equals(locations->Out())); 2073 2074 switch (mul->GetResultType()) { 2075 case Primitive::kPrimInt: { 2076 if (second.IsRegister()) { 2077 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>()); 2078 } else if (second.IsConstant()) { 2079 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); 2080 __ imull(first.AsRegister<Register>(), imm); 2081 } else { 2082 DCHECK(second.IsStackSlot()); 2083 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 2084 } 2085 break; 2086 } 2087 2088 case Primitive::kPrimLong: { 2089 Register in1_hi = first.AsRegisterPairHigh<Register>(); 2090 Register in1_lo = first.AsRegisterPairLow<Register>(); 2091 Register eax = locations->GetTemp(0).AsRegister<Register>(); 2092 Register edx = locations->GetTemp(1).AsRegister<Register>(); 2093 2094 DCHECK_EQ(EAX, eax); 2095 DCHECK_EQ(EDX, edx); 2096 2097 // input: in1 - 64 bits, in2 - 64 bits. 2098 // output: in1 2099 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 2100 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 2101 // parts: in1.lo = (in1.lo * in2.lo)[31:0] 2102 if (second.IsConstant()) { 2103 DCHECK(second.GetConstant()->IsLongConstant()); 2104 2105 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 2106 int32_t low_value = Low32Bits(value); 2107 int32_t high_value = High32Bits(value); 2108 Immediate low(low_value); 2109 Immediate high(high_value); 2110 2111 __ movl(eax, high); 2112 // eax <- in1.lo * in2.hi 2113 __ imull(eax, in1_lo); 2114 // in1.hi <- in1.hi * in2.lo 2115 __ imull(in1_hi, low); 2116 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2117 __ addl(in1_hi, eax); 2118 // move in2_lo to eax to prepare for double precision 2119 __ movl(eax, low); 2120 // edx:eax <- in1.lo * in2.lo 2121 __ mull(in1_lo); 2122 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2123 __ addl(in1_hi, edx); 2124 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2125 __ movl(in1_lo, eax); 2126 } else if (second.IsRegisterPair()) { 2127 Register in2_hi = second.AsRegisterPairHigh<Register>(); 2128 Register in2_lo = second.AsRegisterPairLow<Register>(); 2129 2130 __ movl(eax, in2_hi); 2131 // eax <- in1.lo * in2.hi 2132 __ imull(eax, in1_lo); 2133 // in1.hi <- in1.hi * in2.lo 2134 __ imull(in1_hi, in2_lo); 2135 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2136 __ addl(in1_hi, eax); 2137 // move in1_lo to eax to prepare for double precision 2138 __ movl(eax, in1_lo); 2139 // edx:eax <- in1.lo * in2.lo 2140 __ mull(in2_lo); 2141 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2142 __ addl(in1_hi, edx); 2143 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2144 __ movl(in1_lo, eax); 2145 } else { 2146 DCHECK(second.IsDoubleStackSlot()) << second; 2147 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize)); 2148 Address in2_lo(ESP, second.GetStackIndex()); 2149 2150 __ movl(eax, in2_hi); 2151 // eax <- in1.lo * in2.hi 2152 __ imull(eax, in1_lo); 2153 // in1.hi <- in1.hi * in2.lo 2154 __ imull(in1_hi, in2_lo); 2155 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2156 __ addl(in1_hi, eax); 2157 // move in1_lo to eax to prepare for double precision 2158 __ movl(eax, in1_lo); 2159 // edx:eax <- in1.lo * in2.lo 2160 __ mull(in2_lo); 2161 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2162 __ addl(in1_hi, edx); 2163 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2164 __ movl(in1_lo, eax); 2165 } 2166 2167 break; 2168 } 2169 2170 case Primitive::kPrimFloat: { 2171 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2172 break; 2173 } 2174 2175 case Primitive::kPrimDouble: { 2176 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2177 break; 2178 } 2179 2180 default: 2181 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 2182 } 2183} 2184 2185void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset, 2186 uint32_t stack_adjustment, bool is_float) { 2187 if (source.IsStackSlot()) { 2188 DCHECK(is_float); 2189 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment)); 2190 } else if (source.IsDoubleStackSlot()) { 2191 DCHECK(!is_float); 2192 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment)); 2193 } else { 2194 // Write the value to the temporary location on the stack and load to FP stack. 2195 if (is_float) { 2196 Location stack_temp = Location::StackSlot(temp_offset); 2197 codegen_->Move32(stack_temp, source); 2198 __ flds(Address(ESP, temp_offset)); 2199 } else { 2200 Location stack_temp = Location::DoubleStackSlot(temp_offset); 2201 codegen_->Move64(stack_temp, source); 2202 __ fldl(Address(ESP, temp_offset)); 2203 } 2204 } 2205} 2206 2207void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) { 2208 Primitive::Type type = rem->GetResultType(); 2209 bool is_float = type == Primitive::kPrimFloat; 2210 size_t elem_size = Primitive::ComponentSize(type); 2211 LocationSummary* locations = rem->GetLocations(); 2212 Location first = locations->InAt(0); 2213 Location second = locations->InAt(1); 2214 Location out = locations->Out(); 2215 2216 // Create stack space for 2 elements. 2217 // TODO: enhance register allocator to ask for stack temporaries. 2218 __ subl(ESP, Immediate(2 * elem_size)); 2219 2220 // Load the values to the FP stack in reverse order, using temporaries if needed. 2221 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float); 2222 PushOntoFPStack(first, 0, 2 * elem_size, is_float); 2223 2224 // Loop doing FPREM until we stabilize. 2225 Label retry; 2226 __ Bind(&retry); 2227 __ fprem(); 2228 2229 // Move FP status to AX. 2230 __ fstsw(); 2231 2232 // And see if the argument reduction is complete. This is signaled by the 2233 // C2 FPU flag bit set to 0. 2234 __ andl(EAX, Immediate(kC2ConditionMask)); 2235 __ j(kNotEqual, &retry); 2236 2237 // We have settled on the final value. Retrieve it into an XMM register. 2238 // Store FP top of stack to real stack. 2239 if (is_float) { 2240 __ fsts(Address(ESP, 0)); 2241 } else { 2242 __ fstl(Address(ESP, 0)); 2243 } 2244 2245 // Pop the 2 items from the FP stack. 2246 __ fucompp(); 2247 2248 // Load the value from the stack into an XMM register. 2249 DCHECK(out.IsFpuRegister()) << out; 2250 if (is_float) { 2251 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); 2252 } else { 2253 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); 2254 } 2255 2256 // And remove the temporary stack space we allocated. 2257 __ addl(ESP, Immediate(2 * elem_size)); 2258} 2259 2260void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) { 2261 DCHECK(instruction->IsDiv() || instruction->IsRem()); 2262 2263 LocationSummary* locations = instruction->GetLocations(); 2264 Location out = locations->Out(); 2265 Location first = locations->InAt(0); 2266 Location second = locations->InAt(1); 2267 bool is_div = instruction->IsDiv(); 2268 2269 switch (instruction->GetResultType()) { 2270 case Primitive::kPrimInt: { 2271 Register second_reg = second.AsRegister<Register>(); 2272 DCHECK_EQ(EAX, first.AsRegister<Register>()); 2273 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>()); 2274 2275 SlowPathCodeX86* slow_path = 2276 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(), 2277 is_div); 2278 codegen_->AddSlowPath(slow_path); 2279 2280 // 0x80000000/-1 triggers an arithmetic exception! 2281 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so 2282 // it's safe to just use negl instead of more complex comparisons. 2283 2284 __ cmpl(second_reg, Immediate(-1)); 2285 __ j(kEqual, slow_path->GetEntryLabel()); 2286 2287 // edx:eax <- sign-extended of eax 2288 __ cdq(); 2289 // eax = quotient, edx = remainder 2290 __ idivl(second_reg); 2291 2292 __ Bind(slow_path->GetExitLabel()); 2293 break; 2294 } 2295 2296 case Primitive::kPrimLong: { 2297 InvokeRuntimeCallingConvention calling_convention; 2298 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 2299 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 2300 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 2301 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 2302 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); 2303 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); 2304 2305 if (is_div) { 2306 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv))); 2307 } else { 2308 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod))); 2309 } 2310 uint32_t dex_pc = is_div 2311 ? instruction->AsDiv()->GetDexPc() 2312 : instruction->AsRem()->GetDexPc(); 2313 codegen_->RecordPcInfo(instruction, dex_pc); 2314 2315 break; 2316 } 2317 2318 default: 2319 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType(); 2320 } 2321} 2322 2323void LocationsBuilderX86::VisitDiv(HDiv* div) { 2324 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong) 2325 ? LocationSummary::kCall 2326 : LocationSummary::kNoCall; 2327 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); 2328 2329 switch (div->GetResultType()) { 2330 case Primitive::kPrimInt: { 2331 locations->SetInAt(0, Location::RegisterLocation(EAX)); 2332 locations->SetInAt(1, Location::RequiresRegister()); 2333 locations->SetOut(Location::SameAsFirstInput()); 2334 // Intel uses edx:eax as the dividend. 2335 locations->AddTemp(Location::RegisterLocation(EDX)); 2336 break; 2337 } 2338 case Primitive::kPrimLong: { 2339 InvokeRuntimeCallingConvention calling_convention; 2340 locations->SetInAt(0, Location::RegisterPairLocation( 2341 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 2342 locations->SetInAt(1, Location::RegisterPairLocation( 2343 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 2344 // Runtime helper puts the result in EAX, EDX. 2345 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 2346 break; 2347 } 2348 case Primitive::kPrimFloat: 2349 case Primitive::kPrimDouble: { 2350 locations->SetInAt(0, Location::RequiresFpuRegister()); 2351 locations->SetInAt(1, Location::RequiresFpuRegister()); 2352 locations->SetOut(Location::SameAsFirstInput()); 2353 break; 2354 } 2355 2356 default: 2357 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 2358 } 2359} 2360 2361void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { 2362 LocationSummary* locations = div->GetLocations(); 2363 Location out = locations->Out(); 2364 Location first = locations->InAt(0); 2365 Location second = locations->InAt(1); 2366 2367 switch (div->GetResultType()) { 2368 case Primitive::kPrimInt: 2369 case Primitive::kPrimLong: { 2370 GenerateDivRemIntegral(div); 2371 break; 2372 } 2373 2374 case Primitive::kPrimFloat: { 2375 DCHECK(first.Equals(out)); 2376 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2377 break; 2378 } 2379 2380 case Primitive::kPrimDouble: { 2381 DCHECK(first.Equals(out)); 2382 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2383 break; 2384 } 2385 2386 default: 2387 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 2388 } 2389} 2390 2391void LocationsBuilderX86::VisitRem(HRem* rem) { 2392 Primitive::Type type = rem->GetResultType(); 2393 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong) 2394 ? LocationSummary::kCall 2395 : LocationSummary::kNoCall; 2396 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); 2397 2398 switch (type) { 2399 case Primitive::kPrimInt: { 2400 locations->SetInAt(0, Location::RegisterLocation(EAX)); 2401 locations->SetInAt(1, Location::RequiresRegister()); 2402 locations->SetOut(Location::RegisterLocation(EDX)); 2403 break; 2404 } 2405 case Primitive::kPrimLong: { 2406 InvokeRuntimeCallingConvention calling_convention; 2407 locations->SetInAt(0, Location::RegisterPairLocation( 2408 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 2409 locations->SetInAt(1, Location::RegisterPairLocation( 2410 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 2411 // Runtime helper puts the result in EAX, EDX. 2412 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 2413 break; 2414 } 2415 case Primitive::kPrimDouble: 2416 case Primitive::kPrimFloat: { 2417 locations->SetInAt(0, Location::Any()); 2418 locations->SetInAt(1, Location::Any()); 2419 locations->SetOut(Location::RequiresFpuRegister()); 2420 locations->AddTemp(Location::RegisterLocation(EAX)); 2421 break; 2422 } 2423 2424 default: 2425 LOG(FATAL) << "Unexpected rem type " << type; 2426 } 2427} 2428 2429void InstructionCodeGeneratorX86::VisitRem(HRem* rem) { 2430 Primitive::Type type = rem->GetResultType(); 2431 switch (type) { 2432 case Primitive::kPrimInt: 2433 case Primitive::kPrimLong: { 2434 GenerateDivRemIntegral(rem); 2435 break; 2436 } 2437 case Primitive::kPrimFloat: 2438 case Primitive::kPrimDouble: { 2439 GenerateRemFP(rem); 2440 break; 2441 } 2442 default: 2443 LOG(FATAL) << "Unexpected rem type " << type; 2444 } 2445} 2446 2447void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2448 LocationSummary* locations = 2449 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2450 switch (instruction->GetType()) { 2451 case Primitive::kPrimInt: { 2452 locations->SetInAt(0, Location::Any()); 2453 break; 2454 } 2455 case Primitive::kPrimLong: { 2456 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 2457 if (!instruction->IsConstant()) { 2458 locations->AddTemp(Location::RequiresRegister()); 2459 } 2460 break; 2461 } 2462 default: 2463 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType(); 2464 } 2465 if (instruction->HasUses()) { 2466 locations->SetOut(Location::SameAsFirstInput()); 2467 } 2468} 2469 2470void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2471 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction); 2472 codegen_->AddSlowPath(slow_path); 2473 2474 LocationSummary* locations = instruction->GetLocations(); 2475 Location value = locations->InAt(0); 2476 2477 switch (instruction->GetType()) { 2478 case Primitive::kPrimInt: { 2479 if (value.IsRegister()) { 2480 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>()); 2481 __ j(kEqual, slow_path->GetEntryLabel()); 2482 } else if (value.IsStackSlot()) { 2483 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0)); 2484 __ j(kEqual, slow_path->GetEntryLabel()); 2485 } else { 2486 DCHECK(value.IsConstant()) << value; 2487 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) { 2488 __ jmp(slow_path->GetEntryLabel()); 2489 } 2490 } 2491 break; 2492 } 2493 case Primitive::kPrimLong: { 2494 if (value.IsRegisterPair()) { 2495 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2496 __ movl(temp, value.AsRegisterPairLow<Register>()); 2497 __ orl(temp, value.AsRegisterPairHigh<Register>()); 2498 __ j(kEqual, slow_path->GetEntryLabel()); 2499 } else { 2500 DCHECK(value.IsConstant()) << value; 2501 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) { 2502 __ jmp(slow_path->GetEntryLabel()); 2503 } 2504 } 2505 break; 2506 } 2507 default: 2508 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType(); 2509 } 2510} 2511 2512void LocationsBuilderX86::HandleShift(HBinaryOperation* op) { 2513 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 2514 2515 LocationSummary* locations = 2516 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall); 2517 2518 switch (op->GetResultType()) { 2519 case Primitive::kPrimInt: { 2520 locations->SetInAt(0, Location::RequiresRegister()); 2521 // The shift count needs to be in CL. 2522 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1))); 2523 locations->SetOut(Location::SameAsFirstInput()); 2524 break; 2525 } 2526 case Primitive::kPrimLong: { 2527 locations->SetInAt(0, Location::RequiresRegister()); 2528 // The shift count needs to be in CL. 2529 locations->SetInAt(1, Location::RegisterLocation(ECX)); 2530 locations->SetOut(Location::SameAsFirstInput()); 2531 break; 2532 } 2533 default: 2534 LOG(FATAL) << "Unexpected op type " << op->GetResultType(); 2535 } 2536} 2537 2538void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) { 2539 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 2540 2541 LocationSummary* locations = op->GetLocations(); 2542 Location first = locations->InAt(0); 2543 Location second = locations->InAt(1); 2544 DCHECK(first.Equals(locations->Out())); 2545 2546 switch (op->GetResultType()) { 2547 case Primitive::kPrimInt: { 2548 Register first_reg = first.AsRegister<Register>(); 2549 if (second.IsRegister()) { 2550 Register second_reg = second.AsRegister<Register>(); 2551 DCHECK_EQ(ECX, second_reg); 2552 if (op->IsShl()) { 2553 __ shll(first_reg, second_reg); 2554 } else if (op->IsShr()) { 2555 __ sarl(first_reg, second_reg); 2556 } else { 2557 __ shrl(first_reg, second_reg); 2558 } 2559 } else { 2560 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue); 2561 if (op->IsShl()) { 2562 __ shll(first_reg, imm); 2563 } else if (op->IsShr()) { 2564 __ sarl(first_reg, imm); 2565 } else { 2566 __ shrl(first_reg, imm); 2567 } 2568 } 2569 break; 2570 } 2571 case Primitive::kPrimLong: { 2572 Register second_reg = second.AsRegister<Register>(); 2573 DCHECK_EQ(ECX, second_reg); 2574 if (op->IsShl()) { 2575 GenerateShlLong(first, second_reg); 2576 } else if (op->IsShr()) { 2577 GenerateShrLong(first, second_reg); 2578 } else { 2579 GenerateUShrLong(first, second_reg); 2580 } 2581 break; 2582 } 2583 default: 2584 LOG(FATAL) << "Unexpected op type " << op->GetResultType(); 2585 } 2586} 2587 2588void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) { 2589 Label done; 2590 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter); 2591 __ shll(loc.AsRegisterPairLow<Register>(), shifter); 2592 __ testl(shifter, Immediate(32)); 2593 __ j(kEqual, &done); 2594 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>()); 2595 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0)); 2596 __ Bind(&done); 2597} 2598 2599void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) { 2600 Label done; 2601 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); 2602 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter); 2603 __ testl(shifter, Immediate(32)); 2604 __ j(kEqual, &done); 2605 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); 2606 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31)); 2607 __ Bind(&done); 2608} 2609 2610void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) { 2611 Label done; 2612 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); 2613 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter); 2614 __ testl(shifter, Immediate(32)); 2615 __ j(kEqual, &done); 2616 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); 2617 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0)); 2618 __ Bind(&done); 2619} 2620 2621void LocationsBuilderX86::VisitShl(HShl* shl) { 2622 HandleShift(shl); 2623} 2624 2625void InstructionCodeGeneratorX86::VisitShl(HShl* shl) { 2626 HandleShift(shl); 2627} 2628 2629void LocationsBuilderX86::VisitShr(HShr* shr) { 2630 HandleShift(shr); 2631} 2632 2633void InstructionCodeGeneratorX86::VisitShr(HShr* shr) { 2634 HandleShift(shr); 2635} 2636 2637void LocationsBuilderX86::VisitUShr(HUShr* ushr) { 2638 HandleShift(ushr); 2639} 2640 2641void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) { 2642 HandleShift(ushr); 2643} 2644 2645void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { 2646 LocationSummary* locations = 2647 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2648 locations->SetOut(Location::RegisterLocation(EAX)); 2649 InvokeRuntimeCallingConvention calling_convention; 2650 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2651 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2652} 2653 2654void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { 2655 InvokeRuntimeCallingConvention calling_convention; 2656 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 2657 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex())); 2658 2659 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint()))); 2660 2661 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 2662 DCHECK(!codegen_->IsLeafMethod()); 2663} 2664 2665void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) { 2666 LocationSummary* locations = 2667 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2668 locations->SetOut(Location::RegisterLocation(EAX)); 2669 InvokeRuntimeCallingConvention calling_convention; 2670 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2671 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2672 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2673} 2674 2675void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) { 2676 InvokeRuntimeCallingConvention calling_convention; 2677 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2)); 2678 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex())); 2679 2680 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint()))); 2681 2682 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 2683 DCHECK(!codegen_->IsLeafMethod()); 2684} 2685 2686void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { 2687 LocationSummary* locations = 2688 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2689 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 2690 if (location.IsStackSlot()) { 2691 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2692 } else if (location.IsDoubleStackSlot()) { 2693 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2694 } 2695 locations->SetOut(location); 2696} 2697 2698void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) { 2699 UNUSED(instruction); 2700} 2701 2702void LocationsBuilderX86::VisitNot(HNot* not_) { 2703 LocationSummary* locations = 2704 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 2705 locations->SetInAt(0, Location::RequiresRegister()); 2706 locations->SetOut(Location::SameAsFirstInput()); 2707} 2708 2709void InstructionCodeGeneratorX86::VisitNot(HNot* not_) { 2710 LocationSummary* locations = not_->GetLocations(); 2711 Location in = locations->InAt(0); 2712 Location out = locations->Out(); 2713 DCHECK(in.Equals(out)); 2714 switch (not_->GetResultType()) { 2715 case Primitive::kPrimInt: 2716 __ notl(out.AsRegister<Register>()); 2717 break; 2718 2719 case Primitive::kPrimLong: 2720 __ notl(out.AsRegisterPairLow<Register>()); 2721 __ notl(out.AsRegisterPairHigh<Register>()); 2722 break; 2723 2724 default: 2725 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 2726 } 2727} 2728 2729void LocationsBuilderX86::VisitCompare(HCompare* compare) { 2730 LocationSummary* locations = 2731 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 2732 switch (compare->InputAt(0)->GetType()) { 2733 case Primitive::kPrimLong: { 2734 locations->SetInAt(0, Location::RequiresRegister()); 2735 locations->SetInAt(1, Location::Any()); 2736 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2737 break; 2738 } 2739 case Primitive::kPrimFloat: 2740 case Primitive::kPrimDouble: { 2741 locations->SetInAt(0, Location::RequiresFpuRegister()); 2742 locations->SetInAt(1, Location::RequiresFpuRegister()); 2743 locations->SetOut(Location::RequiresRegister()); 2744 break; 2745 } 2746 default: 2747 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 2748 } 2749} 2750 2751void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) { 2752 LocationSummary* locations = compare->GetLocations(); 2753 Register out = locations->Out().AsRegister<Register>(); 2754 Location left = locations->InAt(0); 2755 Location right = locations->InAt(1); 2756 2757 Label less, greater, done; 2758 switch (compare->InputAt(0)->GetType()) { 2759 case Primitive::kPrimLong: { 2760 Register left_low = left.AsRegisterPairLow<Register>(); 2761 Register left_high = left.AsRegisterPairHigh<Register>(); 2762 int32_t val_low = 0; 2763 int32_t val_high = 0; 2764 bool right_is_const = false; 2765 2766 if (right.IsConstant()) { 2767 DCHECK(right.GetConstant()->IsLongConstant()); 2768 right_is_const = true; 2769 int64_t val = right.GetConstant()->AsLongConstant()->GetValue(); 2770 val_low = Low32Bits(val); 2771 val_high = High32Bits(val); 2772 } 2773 2774 if (right.IsRegisterPair()) { 2775 __ cmpl(left_high, right.AsRegisterPairHigh<Register>()); 2776 } else if (right.IsDoubleStackSlot()) { 2777 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize))); 2778 } else { 2779 DCHECK(right_is_const) << right; 2780 if (val_high == 0) { 2781 __ testl(left_high, left_high); 2782 } else { 2783 __ cmpl(left_high, Immediate(val_high)); 2784 } 2785 } 2786 __ j(kLess, &less); // Signed compare. 2787 __ j(kGreater, &greater); // Signed compare. 2788 if (right.IsRegisterPair()) { 2789 __ cmpl(left_low, right.AsRegisterPairLow<Register>()); 2790 } else if (right.IsDoubleStackSlot()) { 2791 __ cmpl(left_low, Address(ESP, right.GetStackIndex())); 2792 } else { 2793 DCHECK(right_is_const) << right; 2794 if (val_low == 0) { 2795 __ testl(left_low, left_low); 2796 } else { 2797 __ cmpl(left_low, Immediate(val_low)); 2798 } 2799 } 2800 break; 2801 } 2802 case Primitive::kPrimFloat: { 2803 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 2804 __ j(kUnordered, compare->IsGtBias() ? &greater : &less); 2805 break; 2806 } 2807 case Primitive::kPrimDouble: { 2808 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 2809 __ j(kUnordered, compare->IsGtBias() ? &greater : &less); 2810 break; 2811 } 2812 default: 2813 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 2814 } 2815 __ movl(out, Immediate(0)); 2816 __ j(kEqual, &done); 2817 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats). 2818 2819 __ Bind(&greater); 2820 __ movl(out, Immediate(1)); 2821 __ jmp(&done); 2822 2823 __ Bind(&less); 2824 __ movl(out, Immediate(-1)); 2825 2826 __ Bind(&done); 2827} 2828 2829void LocationsBuilderX86::VisitPhi(HPhi* instruction) { 2830 LocationSummary* locations = 2831 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2832 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 2833 locations->SetInAt(i, Location::Any()); 2834 } 2835 locations->SetOut(Location::Any()); 2836} 2837 2838void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) { 2839 UNUSED(instruction); 2840 LOG(FATAL) << "Unreachable"; 2841} 2842 2843void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) { 2844 /* 2845 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence. 2846 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model. 2847 * For those cases, all we need to ensure is that there is a scheduling barrier in place. 2848 */ 2849 switch (kind) { 2850 case MemBarrierKind::kAnyAny: { 2851 __ mfence(); 2852 break; 2853 } 2854 case MemBarrierKind::kAnyStore: 2855 case MemBarrierKind::kLoadAny: 2856 case MemBarrierKind::kStoreStore: { 2857 // nop 2858 break; 2859 } 2860 default: 2861 LOG(FATAL) << "Unexpected memory barrier " << kind; 2862 } 2863} 2864 2865 2866void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) { 2867 Label is_null; 2868 __ testl(value, value); 2869 __ j(kEqual, &is_null); 2870 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value())); 2871 __ movl(temp, object); 2872 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift)); 2873 __ movb(Address(temp, card, TIMES_1, 0), 2874 X86ManagedRegister::FromCpuRegister(card).AsByteRegister()); 2875 __ Bind(&is_null); 2876} 2877 2878void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { 2879 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 2880 LocationSummary* locations = 2881 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2882 locations->SetInAt(0, Location::RequiresRegister()); 2883 2884 // The output overlaps in case of long: we don't want the low move to overwrite 2885 // the object's location. 2886 locations->SetOut(Location::RequiresRegister(), 2887 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap 2888 : Location::kNoOutputOverlap); 2889 2890 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) { 2891 // Long values can be loaded atomically into an XMM using movsd. 2892 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM 2893 // and then copy the XMM into the output 32bits at a time). 2894 locations->AddTemp(Location::RequiresFpuRegister()); 2895 } 2896} 2897 2898void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction, 2899 const FieldInfo& field_info) { 2900 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 2901 2902 LocationSummary* locations = instruction->GetLocations(); 2903 Register base = locations->InAt(0).AsRegister<Register>(); 2904 Location out = locations->Out(); 2905 bool is_volatile = field_info.IsVolatile(); 2906 Primitive::Type field_type = field_info.GetFieldType(); 2907 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 2908 2909 switch (field_type) { 2910 case Primitive::kPrimBoolean: { 2911 __ movzxb(out.AsRegister<Register>(), Address(base, offset)); 2912 break; 2913 } 2914 2915 case Primitive::kPrimByte: { 2916 __ movsxb(out.AsRegister<Register>(), Address(base, offset)); 2917 break; 2918 } 2919 2920 case Primitive::kPrimShort: { 2921 __ movsxw(out.AsRegister<Register>(), Address(base, offset)); 2922 break; 2923 } 2924 2925 case Primitive::kPrimChar: { 2926 __ movzxw(out.AsRegister<Register>(), Address(base, offset)); 2927 break; 2928 } 2929 2930 case Primitive::kPrimInt: 2931 case Primitive::kPrimNot: { 2932 __ movl(out.AsRegister<Register>(), Address(base, offset)); 2933 break; 2934 } 2935 2936 case Primitive::kPrimLong: { 2937 if (is_volatile) { 2938 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 2939 __ movsd(temp, Address(base, offset)); 2940 codegen_->MaybeRecordImplicitNullCheck(instruction); 2941 __ movd(out.AsRegisterPairLow<Register>(), temp); 2942 __ psrlq(temp, Immediate(32)); 2943 __ movd(out.AsRegisterPairHigh<Register>(), temp); 2944 } else { 2945 DCHECK_NE(base, out.AsRegisterPairLow<Register>()); 2946 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset)); 2947 codegen_->MaybeRecordImplicitNullCheck(instruction); 2948 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset)); 2949 } 2950 break; 2951 } 2952 2953 case Primitive::kPrimFloat: { 2954 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset)); 2955 break; 2956 } 2957 2958 case Primitive::kPrimDouble: { 2959 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset)); 2960 break; 2961 } 2962 2963 case Primitive::kPrimVoid: 2964 LOG(FATAL) << "Unreachable type " << field_type; 2965 UNREACHABLE(); 2966 } 2967 2968 // Longs are handled in the switch. 2969 if (field_type != Primitive::kPrimLong) { 2970 codegen_->MaybeRecordImplicitNullCheck(instruction); 2971 } 2972 2973 if (is_volatile) { 2974 GenerateMemoryBarrier(MemBarrierKind::kLoadAny); 2975 } 2976} 2977 2978void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) { 2979 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 2980 2981 LocationSummary* locations = 2982 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2983 locations->SetInAt(0, Location::RequiresRegister()); 2984 bool is_volatile = field_info.IsVolatile(); 2985 Primitive::Type field_type = field_info.GetFieldType(); 2986 bool is_byte_type = (field_type == Primitive::kPrimBoolean) 2987 || (field_type == Primitive::kPrimByte); 2988 2989 // The register allocator does not support multiple 2990 // inputs that die at entry with one in a specific register. 2991 if (is_byte_type) { 2992 // Ensure the value is in a byte register. 2993 locations->SetInAt(1, Location::RegisterLocation(EAX)); 2994 } else { 2995 locations->SetInAt(1, Location::RequiresRegister()); 2996 } 2997 // Temporary registers for the write barrier. 2998 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 2999 locations->AddTemp(Location::RequiresRegister()); 3000 // Ensure the card is in a byte register. 3001 locations->AddTemp(Location::RegisterLocation(ECX)); 3002 } else if (is_volatile && (field_type == Primitive::kPrimLong)) { 3003 // 64bits value can be atomically written to an address with movsd and an XMM register. 3004 // We need two XMM registers because there's no easier way to (bit) copy a register pair 3005 // into a single XMM register (we copy each pair part into the XMMs and then interleave them). 3006 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the 3007 // isolated cases when we need this it isn't worth adding the extra complexity. 3008 locations->AddTemp(Location::RequiresFpuRegister()); 3009 locations->AddTemp(Location::RequiresFpuRegister()); 3010 } 3011} 3012 3013void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction, 3014 const FieldInfo& field_info) { 3015 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 3016 3017 LocationSummary* locations = instruction->GetLocations(); 3018 Register base = locations->InAt(0).AsRegister<Register>(); 3019 Location value = locations->InAt(1); 3020 bool is_volatile = field_info.IsVolatile(); 3021 Primitive::Type field_type = field_info.GetFieldType(); 3022 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 3023 3024 if (is_volatile) { 3025 GenerateMemoryBarrier(MemBarrierKind::kAnyStore); 3026 } 3027 3028 switch (field_type) { 3029 case Primitive::kPrimBoolean: 3030 case Primitive::kPrimByte: { 3031 __ movb(Address(base, offset), value.AsRegister<ByteRegister>()); 3032 break; 3033 } 3034 3035 case Primitive::kPrimShort: 3036 case Primitive::kPrimChar: { 3037 __ movw(Address(base, offset), value.AsRegister<Register>()); 3038 break; 3039 } 3040 3041 case Primitive::kPrimInt: 3042 case Primitive::kPrimNot: { 3043 __ movl(Address(base, offset), value.AsRegister<Register>()); 3044 break; 3045 } 3046 3047 case Primitive::kPrimLong: { 3048 if (is_volatile) { 3049 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 3050 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 3051 __ movd(temp1, value.AsRegisterPairLow<Register>()); 3052 __ movd(temp2, value.AsRegisterPairHigh<Register>()); 3053 __ punpckldq(temp1, temp2); 3054 __ movsd(Address(base, offset), temp1); 3055 codegen_->MaybeRecordImplicitNullCheck(instruction); 3056 } else { 3057 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>()); 3058 codegen_->MaybeRecordImplicitNullCheck(instruction); 3059 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>()); 3060 } 3061 break; 3062 } 3063 3064 case Primitive::kPrimFloat: { 3065 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>()); 3066 break; 3067 } 3068 3069 case Primitive::kPrimDouble: { 3070 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>()); 3071 break; 3072 } 3073 3074 case Primitive::kPrimVoid: 3075 LOG(FATAL) << "Unreachable type " << field_type; 3076 UNREACHABLE(); 3077 } 3078 3079 // Longs are handled in the switch. 3080 if (field_type != Primitive::kPrimLong) { 3081 codegen_->MaybeRecordImplicitNullCheck(instruction); 3082 } 3083 3084 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 3085 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3086 Register card = locations->GetTemp(1).AsRegister<Register>(); 3087 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>()); 3088 } 3089 3090 if (is_volatile) { 3091 GenerateMemoryBarrier(MemBarrierKind::kAnyAny); 3092 } 3093} 3094 3095void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3096 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3097} 3098 3099void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3100 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3101} 3102 3103void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3104 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3105} 3106 3107void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3108 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3109} 3110 3111void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3112 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3113} 3114 3115void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3116 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3117} 3118 3119void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3120 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3121} 3122 3123void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3124 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3125} 3126 3127void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) { 3128 LocationSummary* locations = 3129 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3130 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks() 3131 ? Location::RequiresRegister() 3132 : Location::Any(); 3133 locations->SetInAt(0, loc); 3134 if (instruction->HasUses()) { 3135 locations->SetOut(Location::SameAsFirstInput()); 3136 } 3137} 3138 3139void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) { 3140 if (codegen_->CanMoveNullCheckToUser(instruction)) { 3141 return; 3142 } 3143 LocationSummary* locations = instruction->GetLocations(); 3144 Location obj = locations->InAt(0); 3145 3146 __ testl(EAX, Address(obj.AsRegister<Register>(), 0)); 3147 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 3148} 3149 3150void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) { 3151 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction); 3152 codegen_->AddSlowPath(slow_path); 3153 3154 LocationSummary* locations = instruction->GetLocations(); 3155 Location obj = locations->InAt(0); 3156 3157 if (obj.IsRegister()) { 3158 __ cmpl(obj.AsRegister<Register>(), Immediate(0)); 3159 } else if (obj.IsStackSlot()) { 3160 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0)); 3161 } else { 3162 DCHECK(obj.IsConstant()) << obj; 3163 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 3164 __ jmp(slow_path->GetEntryLabel()); 3165 return; 3166 } 3167 __ j(kEqual, slow_path->GetEntryLabel()); 3168} 3169 3170void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { 3171 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { 3172 GenerateImplicitNullCheck(instruction); 3173 } else { 3174 GenerateExplicitNullCheck(instruction); 3175 } 3176} 3177 3178void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) { 3179 LocationSummary* locations = 3180 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3181 locations->SetInAt(0, Location::RequiresRegister()); 3182 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3183 // The output overlaps in case of long: we don't want the low move to overwrite 3184 // the array's location. 3185 locations->SetOut(Location::RequiresRegister(), 3186 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap 3187 : Location::kNoOutputOverlap); 3188} 3189 3190void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) { 3191 LocationSummary* locations = instruction->GetLocations(); 3192 Register obj = locations->InAt(0).AsRegister<Register>(); 3193 Location index = locations->InAt(1); 3194 3195 Primitive::Type type = instruction->GetType(); 3196 switch (type) { 3197 case Primitive::kPrimBoolean: { 3198 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3199 Register out = locations->Out().AsRegister<Register>(); 3200 if (index.IsConstant()) { 3201 __ movzxb(out, Address(obj, 3202 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset)); 3203 } else { 3204 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset)); 3205 } 3206 break; 3207 } 3208 3209 case Primitive::kPrimByte: { 3210 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 3211 Register out = locations->Out().AsRegister<Register>(); 3212 if (index.IsConstant()) { 3213 __ movsxb(out, Address(obj, 3214 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset)); 3215 } else { 3216 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset)); 3217 } 3218 break; 3219 } 3220 3221 case Primitive::kPrimShort: { 3222 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 3223 Register out = locations->Out().AsRegister<Register>(); 3224 if (index.IsConstant()) { 3225 __ movsxw(out, Address(obj, 3226 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset)); 3227 } else { 3228 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset)); 3229 } 3230 break; 3231 } 3232 3233 case Primitive::kPrimChar: { 3234 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3235 Register out = locations->Out().AsRegister<Register>(); 3236 if (index.IsConstant()) { 3237 __ movzxw(out, Address(obj, 3238 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset)); 3239 } else { 3240 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset)); 3241 } 3242 break; 3243 } 3244 3245 case Primitive::kPrimInt: 3246 case Primitive::kPrimNot: { 3247 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3248 Register out = locations->Out().AsRegister<Register>(); 3249 if (index.IsConstant()) { 3250 __ movl(out, Address(obj, 3251 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset)); 3252 } else { 3253 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset)); 3254 } 3255 break; 3256 } 3257 3258 case Primitive::kPrimLong: { 3259 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3260 Location out = locations->Out(); 3261 DCHECK_NE(obj, out.AsRegisterPairLow<Register>()); 3262 if (index.IsConstant()) { 3263 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3264 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset)); 3265 codegen_->MaybeRecordImplicitNullCheck(instruction); 3266 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize)); 3267 } else { 3268 __ movl(out.AsRegisterPairLow<Register>(), 3269 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset)); 3270 codegen_->MaybeRecordImplicitNullCheck(instruction); 3271 __ movl(out.AsRegisterPairHigh<Register>(), 3272 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize)); 3273 } 3274 break; 3275 } 3276 3277 case Primitive::kPrimFloat: { 3278 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3279 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>(); 3280 if (index.IsConstant()) { 3281 __ movss(out, Address(obj, 3282 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset)); 3283 } else { 3284 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset)); 3285 } 3286 break; 3287 } 3288 3289 case Primitive::kPrimDouble: { 3290 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3291 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>(); 3292 if (index.IsConstant()) { 3293 __ movsd(out, Address(obj, 3294 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset)); 3295 } else { 3296 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset)); 3297 } 3298 break; 3299 } 3300 3301 case Primitive::kPrimVoid: 3302 LOG(FATAL) << "Unreachable type " << type; 3303 UNREACHABLE(); 3304 } 3305 3306 if (type != Primitive::kPrimLong) { 3307 codegen_->MaybeRecordImplicitNullCheck(instruction); 3308 } 3309} 3310 3311void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) { 3312 // This location builder might end up asking to up to four registers, which is 3313 // not currently possible for baseline. The situation in which we need four 3314 // registers cannot be met by baseline though, because it has not run any 3315 // optimization. 3316 3317 Primitive::Type value_type = instruction->GetComponentType(); 3318 bool needs_write_barrier = 3319 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3320 3321 bool needs_runtime_call = instruction->NeedsTypeCheck(); 3322 3323 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3324 instruction, 3325 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall); 3326 3327 if (needs_runtime_call) { 3328 InvokeRuntimeCallingConvention calling_convention; 3329 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3330 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 3331 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 3332 } else { 3333 bool is_byte_type = (value_type == Primitive::kPrimBoolean) 3334 || (value_type == Primitive::kPrimByte); 3335 // We need the inputs to be different than the output in case of long operation. 3336 // In case of a byte operation, the register allocator does not support multiple 3337 // inputs that die at entry with one in a specific register. 3338 locations->SetInAt(0, Location::RequiresRegister()); 3339 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3340 if (is_byte_type) { 3341 // Ensure the value is in a byte register. 3342 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2))); 3343 } else { 3344 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2))); 3345 } 3346 // Temporary registers for the write barrier. 3347 if (needs_write_barrier) { 3348 locations->AddTemp(Location::RequiresRegister()); 3349 // Ensure the card is in a byte register. 3350 locations->AddTemp(Location::RegisterLocation(ECX)); 3351 } 3352 } 3353} 3354 3355void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { 3356 LocationSummary* locations = instruction->GetLocations(); 3357 Register obj = locations->InAt(0).AsRegister<Register>(); 3358 Location index = locations->InAt(1); 3359 Location value = locations->InAt(2); 3360 Primitive::Type value_type = instruction->GetComponentType(); 3361 bool needs_runtime_call = locations->WillCall(); 3362 bool needs_write_barrier = 3363 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3364 3365 switch (value_type) { 3366 case Primitive::kPrimBoolean: 3367 case Primitive::kPrimByte: { 3368 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3369 if (index.IsConstant()) { 3370 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3371 if (value.IsRegister()) { 3372 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>()); 3373 } else { 3374 __ movb(Address(obj, offset), 3375 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3376 } 3377 } else { 3378 if (value.IsRegister()) { 3379 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset), 3380 value.AsRegister<ByteRegister>()); 3381 } else { 3382 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset), 3383 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3384 } 3385 } 3386 codegen_->MaybeRecordImplicitNullCheck(instruction); 3387 break; 3388 } 3389 3390 case Primitive::kPrimShort: 3391 case Primitive::kPrimChar: { 3392 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3393 if (index.IsConstant()) { 3394 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3395 if (value.IsRegister()) { 3396 __ movw(Address(obj, offset), value.AsRegister<Register>()); 3397 } else { 3398 __ movw(Address(obj, offset), 3399 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3400 } 3401 } else { 3402 if (value.IsRegister()) { 3403 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset), 3404 value.AsRegister<Register>()); 3405 } else { 3406 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset), 3407 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3408 } 3409 } 3410 codegen_->MaybeRecordImplicitNullCheck(instruction); 3411 break; 3412 } 3413 3414 case Primitive::kPrimInt: 3415 case Primitive::kPrimNot: { 3416 if (!needs_runtime_call) { 3417 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3418 if (index.IsConstant()) { 3419 size_t offset = 3420 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3421 if (value.IsRegister()) { 3422 __ movl(Address(obj, offset), value.AsRegister<Register>()); 3423 } else { 3424 DCHECK(value.IsConstant()) << value; 3425 __ movl(Address(obj, offset), 3426 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3427 } 3428 } else { 3429 DCHECK(index.IsRegister()) << index; 3430 if (value.IsRegister()) { 3431 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), 3432 value.AsRegister<Register>()); 3433 } else { 3434 DCHECK(value.IsConstant()) << value; 3435 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), 3436 Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 3437 } 3438 } 3439 codegen_->MaybeRecordImplicitNullCheck(instruction); 3440 3441 if (needs_write_barrier) { 3442 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3443 Register card = locations->GetTemp(1).AsRegister<Register>(); 3444 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>()); 3445 } 3446 } else { 3447 DCHECK_EQ(value_type, Primitive::kPrimNot); 3448 DCHECK(!codegen_->IsLeafMethod()); 3449 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject))); 3450 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 3451 } 3452 break; 3453 } 3454 3455 case Primitive::kPrimLong: { 3456 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3457 if (index.IsConstant()) { 3458 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3459 if (value.IsRegisterPair()) { 3460 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>()); 3461 codegen_->MaybeRecordImplicitNullCheck(instruction); 3462 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>()); 3463 } else { 3464 DCHECK(value.IsConstant()); 3465 int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); 3466 __ movl(Address(obj, offset), Immediate(Low32Bits(val))); 3467 codegen_->MaybeRecordImplicitNullCheck(instruction); 3468 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val))); 3469 } 3470 } else { 3471 if (value.IsRegisterPair()) { 3472 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset), 3473 value.AsRegisterPairLow<Register>()); 3474 codegen_->MaybeRecordImplicitNullCheck(instruction); 3475 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize), 3476 value.AsRegisterPairHigh<Register>()); 3477 } else { 3478 DCHECK(value.IsConstant()); 3479 int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); 3480 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset), 3481 Immediate(Low32Bits(val))); 3482 codegen_->MaybeRecordImplicitNullCheck(instruction); 3483 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize), 3484 Immediate(High32Bits(val))); 3485 } 3486 } 3487 break; 3488 } 3489 3490 case Primitive::kPrimFloat: { 3491 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3492 DCHECK(value.IsFpuRegister()); 3493 if (index.IsConstant()) { 3494 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3495 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>()); 3496 } else { 3497 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), 3498 value.AsFpuRegister<XmmRegister>()); 3499 } 3500 break; 3501 } 3502 3503 case Primitive::kPrimDouble: { 3504 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3505 DCHECK(value.IsFpuRegister()); 3506 if (index.IsConstant()) { 3507 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3508 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>()); 3509 } else { 3510 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset), 3511 value.AsFpuRegister<XmmRegister>()); 3512 } 3513 break; 3514 } 3515 3516 case Primitive::kPrimVoid: 3517 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 3518 UNREACHABLE(); 3519 } 3520} 3521 3522void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) { 3523 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 3524 locations->SetInAt(0, Location::RequiresRegister()); 3525 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3526 instruction->SetLocations(locations); 3527} 3528 3529void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) { 3530 LocationSummary* locations = instruction->GetLocations(); 3531 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 3532 Register obj = locations->InAt(0).AsRegister<Register>(); 3533 Register out = locations->Out().AsRegister<Register>(); 3534 __ movl(out, Address(obj, offset)); 3535 codegen_->MaybeRecordImplicitNullCheck(instruction); 3536} 3537 3538void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) { 3539 LocationSummary* locations = 3540 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3541 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 3542 locations->SetInAt(1, Location::RequiresRegister()); 3543 if (instruction->HasUses()) { 3544 locations->SetOut(Location::SameAsFirstInput()); 3545 } 3546} 3547 3548void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) { 3549 LocationSummary* locations = instruction->GetLocations(); 3550 Location index_loc = locations->InAt(0); 3551 Location length_loc = locations->InAt(1); 3552 SlowPathCodeX86* slow_path = 3553 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc); 3554 codegen_->AddSlowPath(slow_path); 3555 3556 Register length = length_loc.AsRegister<Register>(); 3557 if (index_loc.IsConstant()) { 3558 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); 3559 __ cmpl(length, Immediate(value)); 3560 } else { 3561 __ cmpl(length, index_loc.AsRegister<Register>()); 3562 } 3563 __ j(kBelowEqual, slow_path->GetEntryLabel()); 3564} 3565 3566void LocationsBuilderX86::VisitTemporary(HTemporary* temp) { 3567 temp->SetLocations(nullptr); 3568} 3569 3570void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) { 3571 // Nothing to do, this is driven by the code generator. 3572 UNUSED(temp); 3573} 3574 3575void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) { 3576 UNUSED(instruction); 3577 LOG(FATAL) << "Unreachable"; 3578} 3579 3580void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) { 3581 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 3582} 3583 3584void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) { 3585 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 3586} 3587 3588void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) { 3589 HBasicBlock* block = instruction->GetBlock(); 3590 if (block->GetLoopInformation() != nullptr) { 3591 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 3592 // The back edge will generate the suspend check. 3593 return; 3594 } 3595 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 3596 // The goto will generate the suspend check. 3597 return; 3598 } 3599 GenerateSuspendCheck(instruction, nullptr); 3600} 3601 3602void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction, 3603 HBasicBlock* successor) { 3604 SuspendCheckSlowPathX86* slow_path = 3605 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor); 3606 codegen_->AddSlowPath(slow_path); 3607 __ fs()->cmpw(Address::Absolute( 3608 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0)); 3609 if (successor == nullptr) { 3610 __ j(kNotEqual, slow_path->GetEntryLabel()); 3611 __ Bind(slow_path->GetReturnLabel()); 3612 } else { 3613 __ j(kEqual, codegen_->GetLabelOf(successor)); 3614 __ jmp(slow_path->GetEntryLabel()); 3615 } 3616} 3617 3618X86Assembler* ParallelMoveResolverX86::GetAssembler() const { 3619 return codegen_->GetAssembler(); 3620} 3621 3622void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) { 3623 ScratchRegisterScope ensure_scratch( 3624 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 3625 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 3626 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 3627 __ movl(temp_reg, Address(ESP, src + stack_offset)); 3628 __ movl(Address(ESP, dst + stack_offset), temp_reg); 3629} 3630 3631void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) { 3632 ScratchRegisterScope ensure_scratch( 3633 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 3634 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 3635 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 3636 __ movl(temp_reg, Address(ESP, src + stack_offset)); 3637 __ movl(Address(ESP, dst + stack_offset), temp_reg); 3638 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize)); 3639 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg); 3640} 3641 3642void ParallelMoveResolverX86::EmitMove(size_t index) { 3643 MoveOperands* move = moves_.Get(index); 3644 Location source = move->GetSource(); 3645 Location destination = move->GetDestination(); 3646 3647 if (source.IsRegister()) { 3648 if (destination.IsRegister()) { 3649 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 3650 } else { 3651 DCHECK(destination.IsStackSlot()); 3652 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>()); 3653 } 3654 } else if (source.IsFpuRegister()) { 3655 if (destination.IsFpuRegister()) { 3656 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 3657 } else if (destination.IsStackSlot()) { 3658 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 3659 } else { 3660 DCHECK(destination.IsDoubleStackSlot()); 3661 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 3662 } 3663 } else if (source.IsStackSlot()) { 3664 if (destination.IsRegister()) { 3665 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex())); 3666 } else if (destination.IsFpuRegister()) { 3667 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 3668 } else { 3669 DCHECK(destination.IsStackSlot()); 3670 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex()); 3671 } 3672 } else if (source.IsDoubleStackSlot()) { 3673 if (destination.IsFpuRegister()) { 3674 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 3675 } else { 3676 DCHECK(destination.IsDoubleStackSlot()) << destination; 3677 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex()); 3678 } 3679 } else if (source.IsConstant()) { 3680 HConstant* constant = source.GetConstant(); 3681 if (constant->IsIntConstant() || constant->IsNullConstant()) { 3682 int32_t value = CodeGenerator::GetInt32ValueOf(constant); 3683 if (destination.IsRegister()) { 3684 if (value == 0) { 3685 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>()); 3686 } else { 3687 __ movl(destination.AsRegister<Register>(), Immediate(value)); 3688 } 3689 } else { 3690 DCHECK(destination.IsStackSlot()) << destination; 3691 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value)); 3692 } 3693 } else if (constant->IsFloatConstant()) { 3694 float fp_value = constant->AsFloatConstant()->GetValue(); 3695 int32_t value = bit_cast<int32_t, float>(fp_value); 3696 Immediate imm(value); 3697 if (destination.IsFpuRegister()) { 3698 XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); 3699 if (value == 0) { 3700 // Easy handling of 0.0. 3701 __ xorps(dest, dest); 3702 } else { 3703 ScratchRegisterScope ensure_scratch( 3704 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 3705 Register temp = static_cast<Register>(ensure_scratch.GetRegister()); 3706 __ movl(temp, Immediate(value)); 3707 __ movd(dest, temp); 3708 } 3709 } else { 3710 DCHECK(destination.IsStackSlot()) << destination; 3711 __ movl(Address(ESP, destination.GetStackIndex()), imm); 3712 } 3713 } else if (constant->IsLongConstant()) { 3714 int64_t value = constant->AsLongConstant()->GetValue(); 3715 int32_t low_value = Low32Bits(value); 3716 int32_t high_value = High32Bits(value); 3717 Immediate low(low_value); 3718 Immediate high(high_value); 3719 if (destination.IsDoubleStackSlot()) { 3720 __ movl(Address(ESP, destination.GetStackIndex()), low); 3721 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high); 3722 } else { 3723 __ movl(destination.AsRegisterPairLow<Register>(), low); 3724 __ movl(destination.AsRegisterPairHigh<Register>(), high); 3725 } 3726 } else { 3727 DCHECK(constant->IsDoubleConstant()); 3728 double dbl_value = constant->AsDoubleConstant()->GetValue(); 3729 int64_t value = bit_cast<int64_t, double>(dbl_value); 3730 int32_t low_value = Low32Bits(value); 3731 int32_t high_value = High32Bits(value); 3732 Immediate low(low_value); 3733 Immediate high(high_value); 3734 if (destination.IsFpuRegister()) { 3735 XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); 3736 if (value == 0) { 3737 // Easy handling of 0.0. 3738 __ xorpd(dest, dest); 3739 } else { 3740 __ pushl(high); 3741 __ pushl(low); 3742 __ movsd(dest, Address(ESP, 0)); 3743 __ addl(ESP, Immediate(8)); 3744 } 3745 } else { 3746 DCHECK(destination.IsDoubleStackSlot()) << destination; 3747 __ movl(Address(ESP, destination.GetStackIndex()), low); 3748 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high); 3749 } 3750 } 3751 } else { 3752 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source; 3753 } 3754} 3755 3756void ParallelMoveResolverX86::Exchange(Register reg, int mem) { 3757 Register suggested_scratch = reg == EAX ? EBX : EAX; 3758 ScratchRegisterScope ensure_scratch( 3759 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters()); 3760 3761 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 3762 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset)); 3763 __ movl(Address(ESP, mem + stack_offset), reg); 3764 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister())); 3765} 3766 3767void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) { 3768 ScratchRegisterScope ensure_scratch( 3769 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 3770 3771 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 3772 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 3773 __ movl(temp_reg, Address(ESP, mem + stack_offset)); 3774 __ movss(Address(ESP, mem + stack_offset), reg); 3775 __ movd(reg, temp_reg); 3776} 3777 3778void ParallelMoveResolverX86::Exchange(int mem1, int mem2) { 3779 ScratchRegisterScope ensure_scratch1( 3780 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 3781 3782 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX; 3783 ScratchRegisterScope ensure_scratch2( 3784 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters()); 3785 3786 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0; 3787 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0; 3788 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset)); 3789 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset)); 3790 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister())); 3791 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister())); 3792} 3793 3794void ParallelMoveResolverX86::EmitSwap(size_t index) { 3795 MoveOperands* move = moves_.Get(index); 3796 Location source = move->GetSource(); 3797 Location destination = move->GetDestination(); 3798 3799 if (source.IsRegister() && destination.IsRegister()) { 3800 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 3801 } else if (source.IsRegister() && destination.IsStackSlot()) { 3802 Exchange(source.AsRegister<Register>(), destination.GetStackIndex()); 3803 } else if (source.IsStackSlot() && destination.IsRegister()) { 3804 Exchange(destination.AsRegister<Register>(), source.GetStackIndex()); 3805 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 3806 Exchange(destination.GetStackIndex(), source.GetStackIndex()); 3807 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { 3808 // Use XOR Swap algorithm to avoid a temporary. 3809 DCHECK_NE(source.reg(), destination.reg()); 3810 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 3811 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>()); 3812 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 3813 } else if (source.IsFpuRegister() && destination.IsStackSlot()) { 3814 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex()); 3815 } else if (destination.IsFpuRegister() && source.IsStackSlot()) { 3816 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex()); 3817 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) { 3818 // Take advantage of the 16 bytes in the XMM register. 3819 XmmRegister reg = source.AsFpuRegister<XmmRegister>(); 3820 Address stack(ESP, destination.GetStackIndex()); 3821 // Load the double into the high doubleword. 3822 __ movhpd(reg, stack); 3823 3824 // Store the low double into the destination. 3825 __ movsd(stack, reg); 3826 3827 // Move the high double to the low double. 3828 __ psrldq(reg, Immediate(8)); 3829 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) { 3830 // Take advantage of the 16 bytes in the XMM register. 3831 XmmRegister reg = destination.AsFpuRegister<XmmRegister>(); 3832 Address stack(ESP, source.GetStackIndex()); 3833 // Load the double into the high doubleword. 3834 __ movhpd(reg, stack); 3835 3836 // Store the low double into the destination. 3837 __ movsd(stack, reg); 3838 3839 // Move the high double to the low double. 3840 __ psrldq(reg, Immediate(8)); 3841 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) { 3842 Exchange(destination.GetStackIndex(), source.GetStackIndex()); 3843 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize)); 3844 } else { 3845 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination; 3846 } 3847} 3848 3849void ParallelMoveResolverX86::SpillScratch(int reg) { 3850 __ pushl(static_cast<Register>(reg)); 3851} 3852 3853void ParallelMoveResolverX86::RestoreScratch(int reg) { 3854 __ popl(static_cast<Register>(reg)); 3855} 3856 3857void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { 3858 LocationSummary::CallKind call_kind = cls->CanCallRuntime() 3859 ? LocationSummary::kCallOnSlowPath 3860 : LocationSummary::kNoCall; 3861 LocationSummary* locations = 3862 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 3863 locations->SetOut(Location::RequiresRegister()); 3864} 3865 3866void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { 3867 Register out = cls->GetLocations()->Out().AsRegister<Register>(); 3868 if (cls->IsReferrersClass()) { 3869 DCHECK(!cls->CanCallRuntime()); 3870 DCHECK(!cls->MustGenerateClinitCheck()); 3871 codegen_->LoadCurrentMethod(out); 3872 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); 3873 } else { 3874 DCHECK(cls->CanCallRuntime()); 3875 codegen_->LoadCurrentMethod(out); 3876 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); 3877 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); 3878 3879 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( 3880 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 3881 codegen_->AddSlowPath(slow_path); 3882 __ testl(out, out); 3883 __ j(kEqual, slow_path->GetEntryLabel()); 3884 if (cls->MustGenerateClinitCheck()) { 3885 GenerateClassInitializationCheck(slow_path, out); 3886 } else { 3887 __ Bind(slow_path->GetExitLabel()); 3888 } 3889 } 3890} 3891 3892void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) { 3893 LocationSummary* locations = 3894 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 3895 locations->SetInAt(0, Location::RequiresRegister()); 3896 if (check->HasUses()) { 3897 locations->SetOut(Location::SameAsFirstInput()); 3898 } 3899} 3900 3901void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) { 3902 // We assume the class to not be null. 3903 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( 3904 check->GetLoadClass(), check, check->GetDexPc(), true); 3905 codegen_->AddSlowPath(slow_path); 3906 GenerateClassInitializationCheck(slow_path, 3907 check->GetLocations()->InAt(0).AsRegister<Register>()); 3908} 3909 3910void InstructionCodeGeneratorX86::GenerateClassInitializationCheck( 3911 SlowPathCodeX86* slow_path, Register class_reg) { 3912 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), 3913 Immediate(mirror::Class::kStatusInitialized)); 3914 __ j(kLess, slow_path->GetEntryLabel()); 3915 __ Bind(slow_path->GetExitLabel()); 3916 // No need for memory fence, thanks to the X86 memory model. 3917} 3918 3919void LocationsBuilderX86::VisitLoadString(HLoadString* load) { 3920 LocationSummary* locations = 3921 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 3922 locations->SetOut(Location::RequiresRegister()); 3923} 3924 3925void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) { 3926 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load); 3927 codegen_->AddSlowPath(slow_path); 3928 3929 Register out = load->GetLocations()->Out().AsRegister<Register>(); 3930 codegen_->LoadCurrentMethod(out); 3931 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); 3932 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value())); 3933 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex()))); 3934 __ testl(out, out); 3935 __ j(kEqual, slow_path->GetEntryLabel()); 3936 __ Bind(slow_path->GetExitLabel()); 3937} 3938 3939void LocationsBuilderX86::VisitLoadException(HLoadException* load) { 3940 LocationSummary* locations = 3941 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 3942 locations->SetOut(Location::RequiresRegister()); 3943} 3944 3945void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) { 3946 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value()); 3947 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address); 3948 __ fs()->movl(address, Immediate(0)); 3949} 3950 3951void LocationsBuilderX86::VisitThrow(HThrow* instruction) { 3952 LocationSummary* locations = 3953 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3954 InvokeRuntimeCallingConvention calling_convention; 3955 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3956} 3957 3958void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) { 3959 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException))); 3960 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 3961} 3962 3963void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) { 3964 LocationSummary::CallKind call_kind = instruction->IsClassFinal() 3965 ? LocationSummary::kNoCall 3966 : LocationSummary::kCallOnSlowPath; 3967 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 3968 locations->SetInAt(0, Location::RequiresRegister()); 3969 locations->SetInAt(1, Location::Any()); 3970 locations->SetOut(Location::RequiresRegister()); 3971} 3972 3973void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { 3974 LocationSummary* locations = instruction->GetLocations(); 3975 Register obj = locations->InAt(0).AsRegister<Register>(); 3976 Location cls = locations->InAt(1); 3977 Register out = locations->Out().AsRegister<Register>(); 3978 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3979 Label done, zero; 3980 SlowPathCodeX86* slow_path = nullptr; 3981 3982 // Return 0 if `obj` is null. 3983 // TODO: avoid this check if we know obj is not null. 3984 __ testl(obj, obj); 3985 __ j(kEqual, &zero); 3986 __ movl(out, Address(obj, class_offset)); 3987 // Compare the class of `obj` with `cls`. 3988 if (cls.IsRegister()) { 3989 __ cmpl(out, cls.AsRegister<Register>()); 3990 } else { 3991 DCHECK(cls.IsStackSlot()) << cls; 3992 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 3993 } 3994 3995 if (instruction->IsClassFinal()) { 3996 // Classes must be equal for the instanceof to succeed. 3997 __ j(kNotEqual, &zero); 3998 __ movl(out, Immediate(1)); 3999 __ jmp(&done); 4000 } else { 4001 // If the classes are not equal, we go into a slow path. 4002 DCHECK(locations->OnlyCallsOnSlowPath()); 4003 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86( 4004 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); 4005 codegen_->AddSlowPath(slow_path); 4006 __ j(kNotEqual, slow_path->GetEntryLabel()); 4007 __ movl(out, Immediate(1)); 4008 __ jmp(&done); 4009 } 4010 __ Bind(&zero); 4011 __ movl(out, Immediate(0)); 4012 if (slow_path != nullptr) { 4013 __ Bind(slow_path->GetExitLabel()); 4014 } 4015 __ Bind(&done); 4016} 4017 4018void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) { 4019 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 4020 instruction, LocationSummary::kCallOnSlowPath); 4021 locations->SetInAt(0, Location::RequiresRegister()); 4022 locations->SetInAt(1, Location::Any()); 4023 locations->AddTemp(Location::RequiresRegister()); 4024} 4025 4026void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { 4027 LocationSummary* locations = instruction->GetLocations(); 4028 Register obj = locations->InAt(0).AsRegister<Register>(); 4029 Location cls = locations->InAt(1); 4030 Register temp = locations->GetTemp(0).AsRegister<Register>(); 4031 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 4032 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86( 4033 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); 4034 codegen_->AddSlowPath(slow_path); 4035 4036 // TODO: avoid this check if we know obj is not null. 4037 __ testl(obj, obj); 4038 __ j(kEqual, slow_path->GetExitLabel()); 4039 __ movl(temp, Address(obj, class_offset)); 4040 4041 // Compare the class of `obj` with `cls`. 4042 if (cls.IsRegister()) { 4043 __ cmpl(temp, cls.AsRegister<Register>()); 4044 } else { 4045 DCHECK(cls.IsStackSlot()) << cls; 4046 __ cmpl(temp, Address(ESP, cls.GetStackIndex())); 4047 } 4048 4049 __ j(kNotEqual, slow_path->GetEntryLabel()); 4050 __ Bind(slow_path->GetExitLabel()); 4051} 4052 4053void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) { 4054 LocationSummary* locations = 4055 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 4056 InvokeRuntimeCallingConvention calling_convention; 4057 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 4058} 4059 4060void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) { 4061 __ fs()->call(Address::Absolute(instruction->IsEnter() 4062 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject) 4063 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject))); 4064 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 4065} 4066 4067void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 4068void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 4069void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 4070 4071void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) { 4072 LocationSummary* locations = 4073 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 4074 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 4075 || instruction->GetResultType() == Primitive::kPrimLong); 4076 locations->SetInAt(0, Location::RequiresRegister()); 4077 locations->SetInAt(1, Location::Any()); 4078 locations->SetOut(Location::SameAsFirstInput()); 4079} 4080 4081void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) { 4082 HandleBitwiseOperation(instruction); 4083} 4084 4085void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) { 4086 HandleBitwiseOperation(instruction); 4087} 4088 4089void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) { 4090 HandleBitwiseOperation(instruction); 4091} 4092 4093void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) { 4094 LocationSummary* locations = instruction->GetLocations(); 4095 Location first = locations->InAt(0); 4096 Location second = locations->InAt(1); 4097 DCHECK(first.Equals(locations->Out())); 4098 4099 if (instruction->GetResultType() == Primitive::kPrimInt) { 4100 if (second.IsRegister()) { 4101 if (instruction->IsAnd()) { 4102 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>()); 4103 } else if (instruction->IsOr()) { 4104 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>()); 4105 } else { 4106 DCHECK(instruction->IsXor()); 4107 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>()); 4108 } 4109 } else if (second.IsConstant()) { 4110 if (instruction->IsAnd()) { 4111 __ andl(first.AsRegister<Register>(), 4112 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 4113 } else if (instruction->IsOr()) { 4114 __ orl(first.AsRegister<Register>(), 4115 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 4116 } else { 4117 DCHECK(instruction->IsXor()); 4118 __ xorl(first.AsRegister<Register>(), 4119 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 4120 } 4121 } else { 4122 if (instruction->IsAnd()) { 4123 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 4124 } else if (instruction->IsOr()) { 4125 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 4126 } else { 4127 DCHECK(instruction->IsXor()); 4128 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 4129 } 4130 } 4131 } else { 4132 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 4133 if (second.IsRegisterPair()) { 4134 if (instruction->IsAnd()) { 4135 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 4136 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 4137 } else if (instruction->IsOr()) { 4138 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 4139 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 4140 } else { 4141 DCHECK(instruction->IsXor()); 4142 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 4143 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 4144 } 4145 } else if (second.IsDoubleStackSlot()) { 4146 if (instruction->IsAnd()) { 4147 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 4148 __ andl(first.AsRegisterPairHigh<Register>(), 4149 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 4150 } else if (instruction->IsOr()) { 4151 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 4152 __ orl(first.AsRegisterPairHigh<Register>(), 4153 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 4154 } else { 4155 DCHECK(instruction->IsXor()); 4156 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 4157 __ xorl(first.AsRegisterPairHigh<Register>(), 4158 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 4159 } 4160 } else { 4161 DCHECK(second.IsConstant()) << second; 4162 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 4163 int32_t low_value = Low32Bits(value); 4164 int32_t high_value = High32Bits(value); 4165 Immediate low(low_value); 4166 Immediate high(high_value); 4167 Register first_low = first.AsRegisterPairLow<Register>(); 4168 Register first_high = first.AsRegisterPairHigh<Register>(); 4169 if (instruction->IsAnd()) { 4170 if (low_value == 0) { 4171 __ xorl(first_low, first_low); 4172 } else if (low_value != -1) { 4173 __ andl(first_low, low); 4174 } 4175 if (high_value == 0) { 4176 __ xorl(first_high, first_high); 4177 } else if (high_value != -1) { 4178 __ andl(first_high, high); 4179 } 4180 } else if (instruction->IsOr()) { 4181 if (low_value != 0) { 4182 __ orl(first_low, low); 4183 } 4184 if (high_value != 0) { 4185 __ orl(first_high, high); 4186 } 4187 } else { 4188 DCHECK(instruction->IsXor()); 4189 if (low_value != 0) { 4190 __ xorl(first_low, low); 4191 } 4192 if (high_value != 0) { 4193 __ xorl(first_high, high); 4194 } 4195 } 4196 } 4197 } 4198} 4199 4200void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) { 4201 // Nothing to do, this should be removed during prepare for register allocator. 4202 UNUSED(instruction); 4203 LOG(FATAL) << "Unreachable"; 4204} 4205 4206void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) { 4207 // Nothing to do, this should be removed during prepare for register allocator. 4208 UNUSED(instruction); 4209 LOG(FATAL) << "Unreachable"; 4210} 4211 4212} // namespace x86 4213} // namespace art 4214