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