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