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