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