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