Home | History | Annotate | Download | only in optimizing
      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 "entrypoints/quick/quick_entrypoints.h"
     20 #include "gc/accounting/card_table.h"
     21 #include "mirror/array.h"
     22 #include "mirror/art_method.h"
     23 #include "mirror/object_reference.h"
     24 #include "thread.h"
     25 #include "utils/assembler.h"
     26 #include "utils/stack_checks.h"
     27 #include "utils/x86_64/assembler_x86_64.h"
     28 #include "utils/x86_64/managed_register_x86_64.h"
     29 
     30 namespace art {
     31 
     32 x86_64::X86_64ManagedRegister Location::AsX86_64() const {
     33   return reg().AsX86_64();
     34 }
     35 
     36 namespace x86_64 {
     37 
     38 static constexpr bool kExplicitStackOverflowCheck = true;
     39 
     40 // Some x86_64 instructions require a register to be available as temp.
     41 static constexpr Register TMP = R11;
     42 
     43 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
     44 static constexpr int kCurrentMethodStackOffset = 0;
     45 
     46 static Location X86_64CpuLocation(Register reg) {
     47   return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
     48 }
     49 
     50 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
     51 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     52     arraysize(kRuntimeParameterCoreRegisters);
     53 
     54 class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
     55  public:
     56   InvokeRuntimeCallingConvention()
     57       : CallingConvention(kRuntimeParameterCoreRegisters,
     58                           kRuntimeParameterCoreRegistersLength) {}
     59 
     60  private:
     61   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
     62 };
     63 
     64 #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
     65 
     66 class NullCheckSlowPathX86_64 : public SlowPathCode {
     67  public:
     68   explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
     69 
     70   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     71     __ Bind(GetEntryLabel());
     72     __ gs()->call(
     73         Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
     74     codegen->RecordPcInfo(dex_pc_);
     75   }
     76 
     77  private:
     78   const uint32_t dex_pc_;
     79   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
     80 };
     81 
     82 class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
     83  public:
     84   StackOverflowCheckSlowPathX86_64() {}
     85 
     86   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     87     __ Bind(GetEntryLabel());
     88     __ addq(CpuRegister(RSP),
     89             Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
     90     __ gs()->jmp(
     91         Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
     92   }
     93 
     94  private:
     95   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
     96 };
     97 
     98 class BoundsCheckSlowPathX86_64 : public SlowPathCode {
     99  public:
    100   explicit BoundsCheckSlowPathX86_64(uint32_t dex_pc,
    101                                      Location index_location,
    102                                      Location length_location)
    103       : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
    104 
    105   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    106     CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
    107     __ Bind(GetEntryLabel());
    108     InvokeRuntimeCallingConvention calling_convention;
    109     x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
    110     x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
    111     __ gs()->call(Address::Absolute(
    112         QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
    113     codegen->RecordPcInfo(dex_pc_);
    114   }
    115 
    116  private:
    117   const uint32_t dex_pc_;
    118   const Location index_location_;
    119   const Location length_location_;
    120 
    121   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
    122 };
    123 
    124 #undef __
    125 #define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
    126 
    127 inline Condition X86_64Condition(IfCondition cond) {
    128   switch (cond) {
    129     case kCondEQ: return kEqual;
    130     case kCondNE: return kNotEqual;
    131     case kCondLT: return kLess;
    132     case kCondLE: return kLessEqual;
    133     case kCondGT: return kGreater;
    134     case kCondGE: return kGreaterEqual;
    135     default:
    136       LOG(FATAL) << "Unknown if condition";
    137   }
    138   return kEqual;
    139 }
    140 
    141 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
    142   stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
    143 }
    144 
    145 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
    146   stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
    147 }
    148 
    149 CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
    150       : CodeGenerator(graph, kNumberOfRegIds),
    151         location_builder_(graph, this),
    152         instruction_visitor_(graph, this),
    153         move_resolver_(graph->GetArena(), this) {}
    154 
    155 size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
    156   return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
    157 }
    158 
    159 InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
    160                                                                CodeGeneratorX86_64* codegen)
    161       : HGraphVisitor(graph),
    162         assembler_(codegen->GetAssembler()),
    163         codegen_(codegen) {}
    164 
    165 ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
    166                                                           bool* blocked_registers) const {
    167   switch (type) {
    168     case Primitive::kPrimLong:
    169     case Primitive::kPrimByte:
    170     case Primitive::kPrimBoolean:
    171     case Primitive::kPrimChar:
    172     case Primitive::kPrimShort:
    173     case Primitive::kPrimInt:
    174     case Primitive::kPrimNot: {
    175       size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
    176       return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
    177     }
    178 
    179     case Primitive::kPrimFloat:
    180     case Primitive::kPrimDouble:
    181       LOG(FATAL) << "Unimplemented register type " << type;
    182 
    183     case Primitive::kPrimVoid:
    184       LOG(FATAL) << "Unreachable type " << type;
    185   }
    186 
    187   return ManagedRegister::NoRegister();
    188 }
    189 
    190 void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
    191   // Stack register is always reserved.
    192   blocked_registers[RSP] = true;
    193 
    194   // Block the register used as TMP.
    195   blocked_registers[TMP] = true;
    196 
    197   // TODO: We currently don't use Quick's callee saved registers.
    198   blocked_registers[RBX] = true;
    199   blocked_registers[RBP] = true;
    200   blocked_registers[R12] = true;
    201   blocked_registers[R13] = true;
    202   blocked_registers[R14] = true;
    203   blocked_registers[R15] = true;
    204 }
    205 
    206 void CodeGeneratorX86_64::GenerateFrameEntry() {
    207   // Create a fake register to mimic Quick.
    208   static const int kFakeReturnRegister = 16;
    209   core_spill_mask_ |= (1 << kFakeReturnRegister);
    210 
    211   // The return PC has already been pushed on the stack.
    212   __ subq(CpuRegister(RSP),
    213           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
    214 
    215   bool skip_overflow_check = IsLeafMethod()
    216       && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
    217 
    218   if (!skip_overflow_check) {
    219     if (kExplicitStackOverflowCheck) {
    220       SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
    221       AddSlowPath(slow_path);
    222 
    223       __ gs()->cmpq(CpuRegister(RSP),
    224                     Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
    225       __ j(kLess, slow_path->GetEntryLabel());
    226     } else {
    227       __ testq(CpuRegister(RAX), Address(
    228           CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
    229     }
    230   }
    231 
    232   __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
    233 }
    234 
    235 void CodeGeneratorX86_64::GenerateFrameExit() {
    236   __ addq(CpuRegister(RSP),
    237           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
    238 }
    239 
    240 void CodeGeneratorX86_64::Bind(Label* label) {
    241   __ Bind(label);
    242 }
    243 
    244 void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
    245   __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
    246 }
    247 
    248 Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
    249   switch (load->GetType()) {
    250     case Primitive::kPrimLong:
    251       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
    252       break;
    253 
    254     case Primitive::kPrimInt:
    255     case Primitive::kPrimNot:
    256       return Location::StackSlot(GetStackSlot(load->GetLocal()));
    257 
    258     case Primitive::kPrimFloat:
    259     case Primitive::kPrimDouble:
    260       LOG(FATAL) << "Unimplemented type " << load->GetType();
    261 
    262     case Primitive::kPrimBoolean:
    263     case Primitive::kPrimByte:
    264     case Primitive::kPrimChar:
    265     case Primitive::kPrimShort:
    266     case Primitive::kPrimVoid:
    267       LOG(FATAL) << "Unexpected type " << load->GetType();
    268   }
    269 
    270   LOG(FATAL) << "Unreachable";
    271   return Location();
    272 }
    273 
    274 void CodeGeneratorX86_64::Move(Location destination, Location source) {
    275   if (source.Equals(destination)) {
    276     return;
    277   }
    278   if (destination.IsRegister()) {
    279     if (source.IsRegister()) {
    280       __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
    281     } else if (source.IsStackSlot()) {
    282       __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
    283     } else {
    284       DCHECK(source.IsDoubleStackSlot());
    285       __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
    286     }
    287   } else if (destination.IsStackSlot()) {
    288     if (source.IsRegister()) {
    289       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
    290     } else {
    291       DCHECK(source.IsStackSlot());
    292       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
    293       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
    294     }
    295   } else {
    296     DCHECK(destination.IsDoubleStackSlot());
    297     if (source.IsRegister()) {
    298       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
    299     } else {
    300       DCHECK(source.IsDoubleStackSlot());
    301       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
    302       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
    303     }
    304   }
    305 }
    306 
    307 void CodeGeneratorX86_64::Move(HInstruction* instruction,
    308                                Location location,
    309                                HInstruction* move_for) {
    310   if (instruction->AsIntConstant() != nullptr) {
    311     Immediate imm(instruction->AsIntConstant()->GetValue());
    312     if (location.IsRegister()) {
    313       __ movl(location.AsX86_64().AsCpuRegister(), imm);
    314     } else {
    315       __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
    316     }
    317   } else if (instruction->AsLongConstant() != nullptr) {
    318     int64_t value = instruction->AsLongConstant()->GetValue();
    319     if (location.IsRegister()) {
    320       __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
    321     } else {
    322       __ movq(CpuRegister(TMP), Immediate(value));
    323       __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
    324     }
    325   } else if (instruction->AsLoadLocal() != nullptr) {
    326     switch (instruction->GetType()) {
    327       case Primitive::kPrimBoolean:
    328       case Primitive::kPrimByte:
    329       case Primitive::kPrimChar:
    330       case Primitive::kPrimShort:
    331       case Primitive::kPrimInt:
    332       case Primitive::kPrimNot:
    333         Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
    334         break;
    335 
    336       case Primitive::kPrimLong:
    337         Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
    338         break;
    339 
    340       default:
    341         LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
    342     }
    343   } else {
    344     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
    345     switch (instruction->GetType()) {
    346       case Primitive::kPrimBoolean:
    347       case Primitive::kPrimByte:
    348       case Primitive::kPrimChar:
    349       case Primitive::kPrimShort:
    350       case Primitive::kPrimInt:
    351       case Primitive::kPrimNot:
    352       case Primitive::kPrimLong:
    353         Move(location, instruction->GetLocations()->Out());
    354         break;
    355 
    356       default:
    357         LOG(FATAL) << "Unimplemented type " << instruction->GetType();
    358     }
    359   }
    360 }
    361 
    362 void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
    363   got->SetLocations(nullptr);
    364 }
    365 
    366 void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
    367   HBasicBlock* successor = got->GetSuccessor();
    368   if (GetGraph()->GetExitBlock() == successor) {
    369     codegen_->GenerateFrameExit();
    370   } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
    371     __ jmp(codegen_->GetLabelOf(successor));
    372   }
    373 }
    374 
    375 void LocationsBuilderX86_64::VisitExit(HExit* exit) {
    376   exit->SetLocations(nullptr);
    377 }
    378 
    379 void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
    380   if (kIsDebugBuild) {
    381     __ Comment("Unreachable");
    382     __ int3();
    383   }
    384 }
    385 
    386 void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
    387   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
    388   HInstruction* cond = if_instr->InputAt(0);
    389   DCHECK(cond->IsCondition());
    390   HCondition* condition = cond->AsCondition();
    391   if (condition->NeedsMaterialization()) {
    392     locations->SetInAt(0, Location::Any());
    393   }
    394   if_instr->SetLocations(locations);
    395 }
    396 
    397 void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
    398   HInstruction* cond = if_instr->InputAt(0);
    399   DCHECK(cond->IsCondition());
    400   HCondition* condition = cond->AsCondition();
    401   if (condition->NeedsMaterialization()) {
    402     // Materialized condition, compare against 0.
    403     Location lhs = if_instr->GetLocations()->InAt(0);
    404     if (lhs.IsRegister()) {
    405       __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
    406     } else {
    407       __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
    408     }
    409     __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
    410   } else {
    411     Location lhs = condition->GetLocations()->InAt(0);
    412     Location rhs = condition->GetLocations()->InAt(1);
    413     if (rhs.IsRegister()) {
    414       __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
    415     } else if (rhs.IsConstant()) {
    416       __ cmpl(lhs.AsX86_64().AsCpuRegister(),
    417               Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
    418     } else {
    419       __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
    420     }
    421     __ j(X86_64Condition(condition->GetCondition()),
    422          codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
    423   }
    424   if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
    425     __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
    426   }
    427 }
    428 
    429 void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
    430   local->SetLocations(nullptr);
    431 }
    432 
    433 void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
    434   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
    435 }
    436 
    437 void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
    438   local->SetLocations(nullptr);
    439 }
    440 
    441 void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
    442   // Nothing to do, this is driven by the code generator.
    443 }
    444 
    445 void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
    446   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
    447   switch (store->InputAt(1)->GetType()) {
    448     case Primitive::kPrimBoolean:
    449     case Primitive::kPrimByte:
    450     case Primitive::kPrimChar:
    451     case Primitive::kPrimShort:
    452     case Primitive::kPrimInt:
    453     case Primitive::kPrimNot:
    454       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
    455       break;
    456 
    457     case Primitive::kPrimLong:
    458       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
    459       break;
    460 
    461     default:
    462       LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
    463   }
    464   store->SetLocations(locations);
    465 }
    466 
    467 void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
    468 }
    469 
    470 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
    471   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
    472   locations->SetInAt(0, Location::RequiresRegister());
    473   locations->SetInAt(1, Location::Any());
    474   if (comp->NeedsMaterialization()) {
    475     locations->SetOut(Location::RequiresRegister());
    476   }
    477   comp->SetLocations(locations);
    478 }
    479 
    480 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
    481   if (comp->NeedsMaterialization()) {
    482     LocationSummary* locations = comp->GetLocations();
    483     if (locations->InAt(1).IsRegister()) {
    484       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    485               locations->InAt(1).AsX86_64().AsCpuRegister());
    486     } else if (locations->InAt(1).IsConstant()) {
    487       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    488               Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
    489     } else {
    490       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    491               Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
    492     }
    493     __ setcc(X86_64Condition(comp->GetCondition()),
    494              comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
    495   }
    496 }
    497 
    498 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
    499   VisitCondition(comp);
    500 }
    501 
    502 void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
    503   VisitCondition(comp);
    504 }
    505 
    506 void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
    507   VisitCondition(comp);
    508 }
    509 
    510 void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
    511   VisitCondition(comp);
    512 }
    513 
    514 void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
    515   VisitCondition(comp);
    516 }
    517 
    518 void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
    519   VisitCondition(comp);
    520 }
    521 
    522 void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
    523   VisitCondition(comp);
    524 }
    525 
    526 void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
    527   VisitCondition(comp);
    528 }
    529 
    530 void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
    531   VisitCondition(comp);
    532 }
    533 
    534 void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
    535   VisitCondition(comp);
    536 }
    537 
    538 void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
    539   VisitCondition(comp);
    540 }
    541 
    542 void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
    543   VisitCondition(comp);
    544 }
    545 
    546 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
    547   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
    548   locations->SetInAt(0, Location::RequiresRegister());
    549   locations->SetInAt(1, Location::RequiresRegister());
    550   locations->SetOut(Location::RequiresRegister());
    551   compare->SetLocations(locations);
    552 }
    553 
    554 void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
    555   Label greater, done;
    556   LocationSummary* locations = compare->GetLocations();
    557   switch (compare->InputAt(0)->GetType()) {
    558     case Primitive::kPrimLong:
    559       __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    560               locations->InAt(1).AsX86_64().AsCpuRegister());
    561       break;
    562     default:
    563       LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
    564   }
    565 
    566   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
    567   __ j(kEqual, &done);
    568   __ j(kGreater, &greater);
    569 
    570   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
    571   __ jmp(&done);
    572 
    573   __ Bind(&greater);
    574   __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
    575 
    576   __ Bind(&done);
    577 }
    578 
    579 void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
    580   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
    581   locations->SetOut(Location::ConstantLocation(constant));
    582   constant->SetLocations(locations);
    583 }
    584 
    585 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
    586 }
    587 
    588 void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
    589   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
    590   locations->SetOut(Location::ConstantLocation(constant));
    591   constant->SetLocations(locations);
    592 }
    593 
    594 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
    595 }
    596 
    597 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
    598   ret->SetLocations(nullptr);
    599 }
    600 
    601 void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
    602   codegen_->GenerateFrameExit();
    603   __ ret();
    604 }
    605 
    606 void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
    607   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
    608   switch (ret->InputAt(0)->GetType()) {
    609     case Primitive::kPrimBoolean:
    610     case Primitive::kPrimByte:
    611     case Primitive::kPrimChar:
    612     case Primitive::kPrimShort:
    613     case Primitive::kPrimInt:
    614     case Primitive::kPrimNot:
    615     case Primitive::kPrimLong:
    616       locations->SetInAt(0, X86_64CpuLocation(RAX));
    617       break;
    618 
    619     default:
    620       LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
    621   }
    622   ret->SetLocations(locations);
    623 }
    624 
    625 void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
    626   if (kIsDebugBuild) {
    627     switch (ret->InputAt(0)->GetType()) {
    628       case Primitive::kPrimBoolean:
    629       case Primitive::kPrimByte:
    630       case Primitive::kPrimChar:
    631       case Primitive::kPrimShort:
    632       case Primitive::kPrimInt:
    633       case Primitive::kPrimNot:
    634       case Primitive::kPrimLong:
    635         DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
    636         break;
    637 
    638       default:
    639         LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
    640     }
    641   }
    642   codegen_->GenerateFrameExit();
    643   __ ret();
    644 }
    645 
    646 Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
    647   switch (type) {
    648     case Primitive::kPrimBoolean:
    649     case Primitive::kPrimByte:
    650     case Primitive::kPrimChar:
    651     case Primitive::kPrimShort:
    652     case Primitive::kPrimInt:
    653     case Primitive::kPrimNot: {
    654       uint32_t index = gp_index_++;
    655       stack_index_++;
    656       if (index < calling_convention.GetNumberOfRegisters()) {
    657         return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
    658       } else {
    659         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
    660       }
    661     }
    662 
    663     case Primitive::kPrimLong: {
    664       uint32_t index = gp_index_;
    665       stack_index_ += 2;
    666       if (index < calling_convention.GetNumberOfRegisters()) {
    667         gp_index_ += 1;
    668         return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
    669       } else {
    670         gp_index_ += 2;
    671         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
    672       }
    673     }
    674 
    675     case Primitive::kPrimDouble:
    676     case Primitive::kPrimFloat:
    677       LOG(FATAL) << "Unimplemented parameter type " << type;
    678       break;
    679 
    680     case Primitive::kPrimVoid:
    681       LOG(FATAL) << "Unexpected parameter type " << type;
    682       break;
    683   }
    684   return Location();
    685 }
    686 
    687 void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
    688   codegen_->MarkNotLeaf();
    689   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
    690   locations->AddTemp(X86_64CpuLocation(RDI));
    691 
    692   InvokeDexCallingConventionVisitor calling_convention_visitor;
    693   for (size_t i = 0; i < invoke->InputCount(); ++i) {
    694     HInstruction* input = invoke->InputAt(i);
    695     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
    696   }
    697 
    698   switch (invoke->GetType()) {
    699     case Primitive::kPrimBoolean:
    700     case Primitive::kPrimByte:
    701     case Primitive::kPrimChar:
    702     case Primitive::kPrimShort:
    703     case Primitive::kPrimInt:
    704     case Primitive::kPrimNot:
    705     case Primitive::kPrimLong:
    706       locations->SetOut(X86_64CpuLocation(RAX));
    707       break;
    708 
    709     case Primitive::kPrimVoid:
    710       break;
    711 
    712     case Primitive::kPrimDouble:
    713     case Primitive::kPrimFloat:
    714       LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
    715       break;
    716   }
    717 
    718   invoke->SetLocations(locations);
    719 }
    720 
    721 void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
    722   CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
    723   uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
    724   size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
    725       invoke->GetIndexInDexCache() * heap_reference_size;
    726 
    727   // TODO: Implement all kinds of calls:
    728   // 1) boot -> boot
    729   // 2) app -> boot
    730   // 3) app -> app
    731   //
    732   // Currently we implement the app -> app logic, which looks up in the resolve cache.
    733 
    734   // temp = method;
    735   LoadCurrentMethod(temp);
    736   // temp = temp->dex_cache_resolved_methods_;
    737   __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
    738   // temp = temp[index_in_cache]
    739   __ movl(temp, Address(temp, index_in_cache));
    740   // (temp + offset_of_quick_compiled_code)()
    741   __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
    742                   kX86_64PointerSize).SizeValue()));
    743 
    744   DCHECK(!codegen_->IsLeafMethod());
    745   codegen_->RecordPcInfo(invoke->GetDexPc());
    746 }
    747 
    748 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
    749   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
    750   switch (add->GetResultType()) {
    751     case Primitive::kPrimInt: {
    752       locations->SetInAt(0, Location::RequiresRegister());
    753       locations->SetInAt(1, Location::Any());
    754       locations->SetOut(Location::SameAsFirstInput());
    755       break;
    756     }
    757     case Primitive::kPrimLong: {
    758       locations->SetInAt(0, Location::RequiresRegister());
    759       locations->SetInAt(1, Location::RequiresRegister());
    760       locations->SetOut(Location::SameAsFirstInput());
    761       break;
    762     }
    763 
    764     case Primitive::kPrimBoolean:
    765     case Primitive::kPrimByte:
    766     case Primitive::kPrimChar:
    767     case Primitive::kPrimShort:
    768       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
    769       break;
    770 
    771     default:
    772       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
    773   }
    774   add->SetLocations(locations);
    775 }
    776 
    777 void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
    778   LocationSummary* locations = add->GetLocations();
    779   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
    780             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
    781   switch (add->GetResultType()) {
    782     case Primitive::kPrimInt: {
    783       if (locations->InAt(1).IsRegister()) {
    784         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
    785                 locations->InAt(1).AsX86_64().AsCpuRegister());
    786       } else if (locations->InAt(1).IsConstant()) {
    787         HConstant* instruction = locations->InAt(1).GetConstant();
    788         Immediate imm(instruction->AsIntConstant()->GetValue());
    789         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
    790       } else {
    791         __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
    792                 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
    793       }
    794       break;
    795     }
    796     case Primitive::kPrimLong: {
    797       __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    798               locations->InAt(1).AsX86_64().AsCpuRegister());
    799       break;
    800     }
    801 
    802     case Primitive::kPrimBoolean:
    803     case Primitive::kPrimByte:
    804     case Primitive::kPrimChar:
    805     case Primitive::kPrimShort:
    806       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
    807       break;
    808 
    809     default:
    810       LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
    811   }
    812 }
    813 
    814 void LocationsBuilderX86_64::VisitSub(HSub* sub) {
    815   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
    816   switch (sub->GetResultType()) {
    817     case Primitive::kPrimInt: {
    818       locations->SetInAt(0, Location::RequiresRegister());
    819       locations->SetInAt(1, Location::Any());
    820       locations->SetOut(Location::SameAsFirstInput());
    821       break;
    822     }
    823     case Primitive::kPrimLong: {
    824       locations->SetInAt(0, Location::RequiresRegister());
    825       locations->SetInAt(1, Location::RequiresRegister());
    826       locations->SetOut(Location::SameAsFirstInput());
    827       break;
    828     }
    829 
    830     case Primitive::kPrimBoolean:
    831     case Primitive::kPrimByte:
    832     case Primitive::kPrimChar:
    833     case Primitive::kPrimShort:
    834       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
    835       break;
    836 
    837     default:
    838       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
    839   }
    840   sub->SetLocations(locations);
    841 }
    842 
    843 void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
    844   LocationSummary* locations = sub->GetLocations();
    845   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
    846             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
    847   switch (sub->GetResultType()) {
    848     case Primitive::kPrimInt: {
    849       if (locations->InAt(1).IsRegister()) {
    850         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
    851                 locations->InAt(1).AsX86_64().AsCpuRegister());
    852       } else if (locations->InAt(1).IsConstant()) {
    853         HConstant* instruction = locations->InAt(1).GetConstant();
    854         Immediate imm(instruction->AsIntConstant()->GetValue());
    855         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
    856       } else {
    857         __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
    858                 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
    859       }
    860       break;
    861     }
    862     case Primitive::kPrimLong: {
    863       __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
    864               locations->InAt(1).AsX86_64().AsCpuRegister());
    865       break;
    866     }
    867 
    868     case Primitive::kPrimBoolean:
    869     case Primitive::kPrimByte:
    870     case Primitive::kPrimChar:
    871     case Primitive::kPrimShort:
    872       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
    873       break;
    874 
    875     default:
    876       LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
    877   }
    878 }
    879 
    880 void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
    881   codegen_->MarkNotLeaf();
    882   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
    883   locations->SetOut(X86_64CpuLocation(RAX));
    884   instruction->SetLocations(locations);
    885 }
    886 
    887 void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
    888   InvokeRuntimeCallingConvention calling_convention;
    889   LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
    890   __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
    891 
    892   __ gs()->call(Address::Absolute(
    893       QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
    894 
    895   DCHECK(!codegen_->IsLeafMethod());
    896   codegen_->RecordPcInfo(instruction->GetDexPc());
    897 }
    898 
    899 void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
    900   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
    901   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
    902   if (location.IsStackSlot()) {
    903     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
    904   } else if (location.IsDoubleStackSlot()) {
    905     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
    906   }
    907   locations->SetOut(location);
    908   instruction->SetLocations(locations);
    909 }
    910 
    911 void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
    912   // Nothing to do, the parameter is already at its location.
    913 }
    914 
    915 void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
    916   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
    917   locations->SetInAt(0, Location::RequiresRegister());
    918   locations->SetOut(Location::SameAsFirstInput());
    919   instruction->SetLocations(locations);
    920 }
    921 
    922 void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
    923   LocationSummary* locations = instruction->GetLocations();
    924   DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
    925             locations->Out().AsX86_64().AsCpuRegister().AsRegister());
    926   __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
    927 }
    928 
    929 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
    930   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
    931   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
    932     locations->SetInAt(i, Location::Any());
    933   }
    934   locations->SetOut(Location::Any());
    935   instruction->SetLocations(locations);
    936 }
    937 
    938 void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
    939   LOG(FATAL) << "Unimplemented";
    940 }
    941 
    942 void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
    943   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
    944   locations->SetInAt(0, Location::RequiresRegister());
    945   locations->SetInAt(1, Location::RequiresRegister());
    946   // Temporary registers for the write barrier.
    947   if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
    948     locations->AddTemp(Location::RequiresRegister());
    949     locations->AddTemp(Location::RequiresRegister());
    950   }
    951   instruction->SetLocations(locations);
    952 }
    953 
    954 void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
    955   LocationSummary* locations = instruction->GetLocations();
    956   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
    957   CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
    958   size_t offset = instruction->GetFieldOffset().SizeValue();
    959   Primitive::Type field_type = instruction->InputAt(1)->GetType();
    960 
    961   switch (field_type) {
    962     case Primitive::kPrimBoolean:
    963     case Primitive::kPrimByte: {
    964       __ movb(Address(obj, offset), value);
    965       break;
    966     }
    967 
    968     case Primitive::kPrimShort:
    969     case Primitive::kPrimChar: {
    970       __ movw(Address(obj, offset), value);
    971       break;
    972     }
    973 
    974     case Primitive::kPrimInt:
    975     case Primitive::kPrimNot: {
    976       __ movl(Address(obj, offset), value);
    977       if (field_type == Primitive::kPrimNot) {
    978         CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
    979         CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
    980         codegen_->MarkGCCard(temp, card, obj, value);
    981       }
    982       break;
    983     }
    984 
    985     case Primitive::kPrimLong: {
    986       __ movq(Address(obj, offset), value);
    987       break;
    988     }
    989 
    990     case Primitive::kPrimFloat:
    991     case Primitive::kPrimDouble:
    992       LOG(FATAL) << "Unimplemented register type " << field_type;
    993 
    994     case Primitive::kPrimVoid:
    995       LOG(FATAL) << "Unreachable type " << field_type;
    996   }
    997 }
    998 
    999 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   1000   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1001   locations->SetInAt(0, Location::RequiresRegister());
   1002   locations->SetOut(Location::RequiresRegister());
   1003   instruction->SetLocations(locations);
   1004 }
   1005 
   1006 void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   1007   LocationSummary* locations = instruction->GetLocations();
   1008   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
   1009   CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1010   size_t offset = instruction->GetFieldOffset().SizeValue();
   1011 
   1012   switch (instruction->GetType()) {
   1013     case Primitive::kPrimBoolean: {
   1014       __ movzxb(out, Address(obj, offset));
   1015       break;
   1016     }
   1017 
   1018     case Primitive::kPrimByte: {
   1019       __ movsxb(out, Address(obj, offset));
   1020       break;
   1021     }
   1022 
   1023     case Primitive::kPrimShort: {
   1024       __ movsxw(out, Address(obj, offset));
   1025       break;
   1026     }
   1027 
   1028     case Primitive::kPrimChar: {
   1029       __ movzxw(out, Address(obj, offset));
   1030       break;
   1031     }
   1032 
   1033     case Primitive::kPrimInt:
   1034     case Primitive::kPrimNot: {
   1035       __ movl(out, Address(obj, offset));
   1036       break;
   1037     }
   1038 
   1039     case Primitive::kPrimLong: {
   1040       __ movq(out, Address(obj, offset));
   1041       break;
   1042     }
   1043 
   1044     case Primitive::kPrimFloat:
   1045     case Primitive::kPrimDouble:
   1046       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
   1047 
   1048     case Primitive::kPrimVoid:
   1049       LOG(FATAL) << "Unreachable type " << instruction->GetType();
   1050   }
   1051 }
   1052 
   1053 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
   1054   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1055   locations->SetInAt(0, Location::Any());
   1056   // TODO: Have a normalization phase that makes this instruction never used.
   1057   locations->SetOut(Location::SameAsFirstInput());
   1058   instruction->SetLocations(locations);
   1059 }
   1060 
   1061 void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
   1062   SlowPathCode* slow_path =
   1063       new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
   1064   codegen_->AddSlowPath(slow_path);
   1065 
   1066   LocationSummary* locations = instruction->GetLocations();
   1067   Location obj = locations->InAt(0);
   1068   DCHECK(obj.Equals(locations->Out()));
   1069 
   1070   if (obj.IsRegister()) {
   1071     __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
   1072   } else {
   1073     DCHECK(locations->InAt(0).IsStackSlot());
   1074     __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
   1075   }
   1076   __ j(kEqual, slow_path->GetEntryLabel());
   1077 }
   1078 
   1079 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
   1080   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1081   locations->SetInAt(0, Location::RequiresRegister());
   1082   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   1083   locations->SetOut(Location::RequiresRegister());
   1084   instruction->SetLocations(locations);
   1085 }
   1086 
   1087 void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
   1088   LocationSummary* locations = instruction->GetLocations();
   1089   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
   1090   Location index = locations->InAt(1);
   1091 
   1092   switch (instruction->GetType()) {
   1093     case Primitive::kPrimBoolean: {
   1094       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   1095       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1096       if (index.IsConstant()) {
   1097         __ movzxb(out, Address(obj,
   1098             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
   1099       } else {
   1100         __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
   1101       }
   1102       break;
   1103     }
   1104 
   1105     case Primitive::kPrimByte: {
   1106       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
   1107       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1108       if (index.IsConstant()) {
   1109         __ movsxb(out, Address(obj,
   1110             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
   1111       } else {
   1112         __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
   1113       }
   1114       break;
   1115     }
   1116 
   1117     case Primitive::kPrimShort: {
   1118       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
   1119       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1120       if (index.IsConstant()) {
   1121         __ movsxw(out, Address(obj,
   1122             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
   1123       } else {
   1124         __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
   1125       }
   1126       break;
   1127     }
   1128 
   1129     case Primitive::kPrimChar: {
   1130       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   1131       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1132       if (index.IsConstant()) {
   1133         __ movzxw(out, Address(obj,
   1134             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
   1135       } else {
   1136         __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
   1137       }
   1138       break;
   1139     }
   1140 
   1141     case Primitive::kPrimInt:
   1142     case Primitive::kPrimNot: {
   1143       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
   1144       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   1145       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1146       if (index.IsConstant()) {
   1147         __ movl(out, Address(obj,
   1148             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
   1149       } else {
   1150         __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
   1151       }
   1152       break;
   1153     }
   1154 
   1155     case Primitive::kPrimLong: {
   1156       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   1157       CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1158       if (index.IsConstant()) {
   1159         __ movq(out, Address(obj,
   1160             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
   1161       } else {
   1162         __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
   1163       }
   1164       break;
   1165     }
   1166 
   1167     case Primitive::kPrimFloat:
   1168     case Primitive::kPrimDouble:
   1169       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
   1170 
   1171     case Primitive::kPrimVoid:
   1172       LOG(FATAL) << "Unreachable type " << instruction->GetType();
   1173   }
   1174 }
   1175 
   1176 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
   1177   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1178   Primitive::Type value_type = instruction->InputAt(2)->GetType();
   1179   if (value_type == Primitive::kPrimNot) {
   1180     InvokeRuntimeCallingConvention calling_convention;
   1181     locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
   1182     locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
   1183     locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
   1184     codegen_->MarkNotLeaf();
   1185   } else {
   1186     locations->SetInAt(0, Location::RequiresRegister());
   1187     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   1188     locations->SetInAt(2, Location::RequiresRegister());
   1189   }
   1190   instruction->SetLocations(locations);
   1191 }
   1192 
   1193 void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
   1194   LocationSummary* locations = instruction->GetLocations();
   1195   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
   1196   Location index = locations->InAt(1);
   1197   Primitive::Type value_type = instruction->InputAt(2)->GetType();
   1198 
   1199   switch (value_type) {
   1200     case Primitive::kPrimBoolean:
   1201     case Primitive::kPrimByte: {
   1202       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   1203       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
   1204       if (index.IsConstant()) {
   1205         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   1206         __ movb(Address(obj, offset), value);
   1207       } else {
   1208         __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
   1209       }
   1210       break;
   1211     }
   1212 
   1213     case Primitive::kPrimShort:
   1214     case Primitive::kPrimChar: {
   1215       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   1216       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
   1217       if (index.IsConstant()) {
   1218         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   1219         __ movw(Address(obj, offset), value);
   1220       } else {
   1221         __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
   1222       }
   1223       break;
   1224     }
   1225 
   1226     case Primitive::kPrimInt: {
   1227       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   1228       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
   1229       if (index.IsConstant()) {
   1230         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   1231         __ movl(Address(obj, offset), value);
   1232       } else {
   1233         __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
   1234       }
   1235       break;
   1236     }
   1237 
   1238     case Primitive::kPrimNot: {
   1239       __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
   1240       DCHECK(!codegen_->IsLeafMethod());
   1241       codegen_->RecordPcInfo(instruction->GetDexPc());
   1242       break;
   1243     }
   1244 
   1245     case Primitive::kPrimLong: {
   1246       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   1247       CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
   1248       if (index.IsConstant()) {
   1249         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   1250         __ movq(Address(obj, offset), value);
   1251       } else {
   1252         __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
   1253       }
   1254       break;
   1255     }
   1256 
   1257     case Primitive::kPrimFloat:
   1258     case Primitive::kPrimDouble:
   1259       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
   1260 
   1261     case Primitive::kPrimVoid:
   1262       LOG(FATAL) << "Unreachable type " << instruction->GetType();
   1263   }
   1264 }
   1265 
   1266 void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
   1267   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1268   locations->SetInAt(0, Location::RequiresRegister());
   1269   locations->SetOut(Location::RequiresRegister());
   1270   instruction->SetLocations(locations);
   1271 }
   1272 
   1273 void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
   1274   LocationSummary* locations = instruction->GetLocations();
   1275   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
   1276   CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
   1277   CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
   1278   __ movl(out, Address(obj, offset));
   1279 }
   1280 
   1281 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
   1282   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   1283   locations->SetInAt(0, Location::RequiresRegister());
   1284   locations->SetInAt(1, Location::RequiresRegister());
   1285   // TODO: Have a normalization phase that makes this instruction never used.
   1286   locations->SetOut(Location::SameAsFirstInput());
   1287   instruction->SetLocations(locations);
   1288 }
   1289 
   1290 void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
   1291   LocationSummary* locations = instruction->GetLocations();
   1292   SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
   1293       instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
   1294   codegen_->AddSlowPath(slow_path);
   1295 
   1296   CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
   1297   CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
   1298 
   1299   __ cmpl(index, length);
   1300   __ j(kAboveEqual, slow_path->GetEntryLabel());
   1301 }
   1302 
   1303 void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
   1304                                      CpuRegister card,
   1305                                      CpuRegister object,
   1306                                      CpuRegister value) {
   1307   Label is_null;
   1308   __ testl(value, value);
   1309   __ j(kEqual, &is_null);
   1310   __ gs()->movq(card, Address::Absolute(
   1311       Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
   1312   __ movq(temp, object);
   1313   __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
   1314   __ movb(Address(temp, card, TIMES_1, 0),  card);
   1315   __ Bind(&is_null);
   1316 }
   1317 
   1318 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
   1319   temp->SetLocations(nullptr);
   1320 }
   1321 
   1322 void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
   1323   // Nothing to do, this is driven by the code generator.
   1324 }
   1325 
   1326 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
   1327   LOG(FATAL) << "Unimplemented";
   1328 }
   1329 
   1330 void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
   1331   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
   1332 }
   1333 
   1334 X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
   1335   return codegen_->GetAssembler();
   1336 }
   1337 
   1338 void ParallelMoveResolverX86_64::EmitMove(size_t index) {
   1339   MoveOperands* move = moves_.Get(index);
   1340   Location source = move->GetSource();
   1341   Location destination = move->GetDestination();
   1342 
   1343   if (source.IsRegister()) {
   1344     if (destination.IsRegister()) {
   1345       __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
   1346     } else if (destination.IsStackSlot()) {
   1347       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
   1348               source.AsX86_64().AsCpuRegister());
   1349     } else {
   1350       DCHECK(destination.IsDoubleStackSlot());
   1351       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
   1352               source.AsX86_64().AsCpuRegister());
   1353     }
   1354   } else if (source.IsStackSlot()) {
   1355     if (destination.IsRegister()) {
   1356       __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
   1357               Address(CpuRegister(RSP), source.GetStackIndex()));
   1358     } else {
   1359       DCHECK(destination.IsStackSlot());
   1360       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
   1361       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
   1362     }
   1363   } else if (source.IsDoubleStackSlot()) {
   1364     if (destination.IsRegister()) {
   1365       __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
   1366               Address(CpuRegister(RSP), source.GetStackIndex()));
   1367     } else {
   1368       DCHECK(destination.IsDoubleStackSlot());
   1369       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
   1370       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
   1371     }
   1372   } else if (source.IsConstant()) {
   1373     HConstant* constant = source.GetConstant();
   1374     if (constant->IsIntConstant()) {
   1375       Immediate imm(constant->AsIntConstant()->GetValue());
   1376       if (destination.IsRegister()) {
   1377         __ movl(destination.AsX86_64().AsCpuRegister(), imm);
   1378       } else {
   1379         __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
   1380       }
   1381     } else if (constant->IsLongConstant()) {
   1382       int64_t value = constant->AsLongConstant()->GetValue();
   1383       if (destination.IsRegister()) {
   1384         __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
   1385       } else {
   1386         __ movq(CpuRegister(TMP), Immediate(value));
   1387         __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
   1388       }
   1389     } else {
   1390       LOG(FATAL) << "Unimplemented constant type";
   1391     }
   1392   } else {
   1393     LOG(FATAL) << "Unimplemented";
   1394   }
   1395 }
   1396 
   1397 void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
   1398   __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
   1399   __ movl(Address(CpuRegister(RSP), mem), reg);
   1400   __ movl(reg, CpuRegister(TMP));
   1401 }
   1402 
   1403 void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
   1404   ScratchRegisterScope ensure_scratch(
   1405       this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
   1406 
   1407   int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
   1408   __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
   1409   __ movl(CpuRegister(ensure_scratch.GetRegister()),
   1410           Address(CpuRegister(RSP), mem2 + stack_offset));
   1411   __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
   1412   __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
   1413           CpuRegister(ensure_scratch.GetRegister()));
   1414 }
   1415 
   1416 void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
   1417   __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
   1418   __ movq(Address(CpuRegister(RSP), mem), reg);
   1419   __ movq(reg, CpuRegister(TMP));
   1420 }
   1421 
   1422 void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
   1423   ScratchRegisterScope ensure_scratch(
   1424       this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
   1425 
   1426   int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
   1427   __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
   1428   __ movq(CpuRegister(ensure_scratch.GetRegister()),
   1429           Address(CpuRegister(RSP), mem2 + stack_offset));
   1430   __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
   1431   __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
   1432           CpuRegister(ensure_scratch.GetRegister()));
   1433 }
   1434 
   1435 void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
   1436   MoveOperands* move = moves_.Get(index);
   1437   Location source = move->GetSource();
   1438   Location destination = move->GetDestination();
   1439 
   1440   if (source.IsRegister() && destination.IsRegister()) {
   1441     __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
   1442   } else if (source.IsRegister() && destination.IsStackSlot()) {
   1443     Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
   1444   } else if (source.IsStackSlot() && destination.IsRegister()) {
   1445     Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
   1446   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
   1447     Exchange32(destination.GetStackIndex(), source.GetStackIndex());
   1448   } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
   1449     Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
   1450   } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
   1451     Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
   1452   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
   1453     Exchange64(destination.GetStackIndex(), source.GetStackIndex());
   1454   } else {
   1455     LOG(FATAL) << "Unimplemented";
   1456   }
   1457 }
   1458 
   1459 
   1460 void ParallelMoveResolverX86_64::SpillScratch(int reg) {
   1461   __ pushq(CpuRegister(reg));
   1462 }
   1463 
   1464 
   1465 void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
   1466   __ popq(CpuRegister(reg));
   1467 }
   1468 
   1469 }  // namespace x86_64
   1470 }  // namespace art
   1471