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