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_arm.h"
     18 
     19 #include "arch/arm/instruction_set_features_arm.h"
     20 #include "art_method.h"
     21 #include "code_generator_utils.h"
     22 #include "compiled_method.h"
     23 #include "entrypoints/quick/quick_entrypoints.h"
     24 #include "gc/accounting/card_table.h"
     25 #include "intrinsics.h"
     26 #include "intrinsics_arm.h"
     27 #include "mirror/array-inl.h"
     28 #include "mirror/class-inl.h"
     29 #include "thread.h"
     30 #include "utils/arm/assembler_arm.h"
     31 #include "utils/arm/managed_register_arm.h"
     32 #include "utils/assembler.h"
     33 #include "utils/stack_checks.h"
     34 
     35 namespace art {
     36 
     37 template<class MirrorType>
     38 class GcRoot;
     39 
     40 namespace arm {
     41 
     42 static bool ExpectedPairLayout(Location location) {
     43   // We expected this for both core and fpu register pairs.
     44   return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
     45 }
     46 
     47 static constexpr int kCurrentMethodStackOffset = 0;
     48 static constexpr Register kMethodRegisterArgument = R0;
     49 
     50 static constexpr Register kCoreAlwaysSpillRegister = R5;
     51 static constexpr Register kCoreCalleeSaves[] =
     52     { R5, R6, R7, R8, R10, R11, LR };
     53 static constexpr SRegister kFpuCalleeSaves[] =
     54     { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
     55 
     56 // D31 cannot be split into two S registers, and the register allocator only works on
     57 // S registers. Therefore there is no need to block it.
     58 static constexpr DRegister DTMP = D31;
     59 
     60 static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
     61 
     62 #define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
     63 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
     64 
     65 class NullCheckSlowPathARM : public SlowPathCode {
     66  public:
     67   explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCode(instruction) {}
     68 
     69   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     70     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     71     __ Bind(GetEntryLabel());
     72     if (instruction_->CanThrowIntoCatchBlock()) {
     73       // Live registers will be restored in the catch block if caught.
     74       SaveLiveRegisters(codegen, instruction_->GetLocations());
     75     }
     76     arm_codegen->InvokeRuntime(
     77         QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
     78     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
     79   }
     80 
     81   bool IsFatal() const OVERRIDE { return true; }
     82 
     83   const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
     84 
     85  private:
     86   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
     87 };
     88 
     89 class DivZeroCheckSlowPathARM : public SlowPathCode {
     90  public:
     91   explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
     92 
     93   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     94     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     95     __ Bind(GetEntryLabel());
     96     if (instruction_->CanThrowIntoCatchBlock()) {
     97       // Live registers will be restored in the catch block if caught.
     98       SaveLiveRegisters(codegen, instruction_->GetLocations());
     99     }
    100     arm_codegen->InvokeRuntime(
    101         QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
    102     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
    103   }
    104 
    105   bool IsFatal() const OVERRIDE { return true; }
    106 
    107   const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
    108 
    109  private:
    110   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
    111 };
    112 
    113 class SuspendCheckSlowPathARM : public SlowPathCode {
    114  public:
    115   SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
    116       : SlowPathCode(instruction), successor_(successor) {}
    117 
    118   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    119     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    120     __ Bind(GetEntryLabel());
    121     SaveLiveRegisters(codegen, instruction_->GetLocations());
    122     arm_codegen->InvokeRuntime(
    123         QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
    124     CheckEntrypointTypes<kQuickTestSuspend, void, void>();
    125     RestoreLiveRegisters(codegen, instruction_->GetLocations());
    126     if (successor_ == nullptr) {
    127       __ b(GetReturnLabel());
    128     } else {
    129       __ b(arm_codegen->GetLabelOf(successor_));
    130     }
    131   }
    132 
    133   Label* GetReturnLabel() {
    134     DCHECK(successor_ == nullptr);
    135     return &return_label_;
    136   }
    137 
    138   HBasicBlock* GetSuccessor() const {
    139     return successor_;
    140   }
    141 
    142   const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
    143 
    144  private:
    145   // If not null, the block to branch to after the suspend check.
    146   HBasicBlock* const successor_;
    147 
    148   // If `successor_` is null, the label to branch to after the suspend check.
    149   Label return_label_;
    150 
    151   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
    152 };
    153 
    154 class BoundsCheckSlowPathARM : public SlowPathCode {
    155  public:
    156   explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
    157       : SlowPathCode(instruction) {}
    158 
    159   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    160     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    161     LocationSummary* locations = instruction_->GetLocations();
    162 
    163     __ Bind(GetEntryLabel());
    164     if (instruction_->CanThrowIntoCatchBlock()) {
    165       // Live registers will be restored in the catch block if caught.
    166       SaveLiveRegisters(codegen, instruction_->GetLocations());
    167     }
    168     // We're moving two locations to locations that could overlap, so we need a parallel
    169     // move resolver.
    170     InvokeRuntimeCallingConvention calling_convention;
    171     codegen->EmitParallelMoves(
    172         locations->InAt(0),
    173         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
    174         Primitive::kPrimInt,
    175         locations->InAt(1),
    176         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
    177         Primitive::kPrimInt);
    178     arm_codegen->InvokeRuntime(
    179         QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
    180     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
    181   }
    182 
    183   bool IsFatal() const OVERRIDE { return true; }
    184 
    185   const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
    186 
    187  private:
    188   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
    189 };
    190 
    191 class LoadClassSlowPathARM : public SlowPathCode {
    192  public:
    193   LoadClassSlowPathARM(HLoadClass* cls,
    194                        HInstruction* at,
    195                        uint32_t dex_pc,
    196                        bool do_clinit)
    197       : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
    198     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
    199   }
    200 
    201   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    202     LocationSummary* locations = at_->GetLocations();
    203 
    204     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    205     __ Bind(GetEntryLabel());
    206     SaveLiveRegisters(codegen, locations);
    207 
    208     InvokeRuntimeCallingConvention calling_convention;
    209     __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
    210     int32_t entry_point_offset = do_clinit_
    211         ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
    212         : QUICK_ENTRY_POINT(pInitializeType);
    213     arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
    214     if (do_clinit_) {
    215       CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
    216     } else {
    217       CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
    218     }
    219 
    220     // Move the class to the desired location.
    221     Location out = locations->Out();
    222     if (out.IsValid()) {
    223       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
    224       arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
    225     }
    226     RestoreLiveRegisters(codegen, locations);
    227     __ b(GetExitLabel());
    228   }
    229 
    230   const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
    231 
    232  private:
    233   // The class this slow path will load.
    234   HLoadClass* const cls_;
    235 
    236   // The instruction where this slow path is happening.
    237   // (Might be the load class or an initialization check).
    238   HInstruction* const at_;
    239 
    240   // The dex PC of `at_`.
    241   const uint32_t dex_pc_;
    242 
    243   // Whether to initialize the class.
    244   const bool do_clinit_;
    245 
    246   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
    247 };
    248 
    249 class LoadStringSlowPathARM : public SlowPathCode {
    250  public:
    251   explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
    252 
    253   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    254     LocationSummary* locations = instruction_->GetLocations();
    255     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
    256 
    257     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    258     __ Bind(GetEntryLabel());
    259     SaveLiveRegisters(codegen, locations);
    260 
    261     InvokeRuntimeCallingConvention calling_convention;
    262     const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
    263     __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
    264     arm_codegen->InvokeRuntime(
    265         QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
    266     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
    267     arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
    268 
    269     RestoreLiveRegisters(codegen, locations);
    270     __ b(GetExitLabel());
    271   }
    272 
    273   const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
    274 
    275  private:
    276   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
    277 };
    278 
    279 class TypeCheckSlowPathARM : public SlowPathCode {
    280  public:
    281   TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
    282       : SlowPathCode(instruction), is_fatal_(is_fatal) {}
    283 
    284   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    285     LocationSummary* locations = instruction_->GetLocations();
    286     Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
    287                                                         : locations->Out();
    288     DCHECK(instruction_->IsCheckCast()
    289            || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
    290 
    291     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    292     __ Bind(GetEntryLabel());
    293 
    294     if (!is_fatal_) {
    295       SaveLiveRegisters(codegen, locations);
    296     }
    297 
    298     // We're moving two locations to locations that could overlap, so we need a parallel
    299     // move resolver.
    300     InvokeRuntimeCallingConvention calling_convention;
    301     codegen->EmitParallelMoves(
    302         locations->InAt(1),
    303         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
    304         Primitive::kPrimNot,
    305         object_class,
    306         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
    307         Primitive::kPrimNot);
    308 
    309     if (instruction_->IsInstanceOf()) {
    310       arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
    311                                  instruction_,
    312                                  instruction_->GetDexPc(),
    313                                  this);
    314       CheckEntrypointTypes<
    315           kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
    316       arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
    317     } else {
    318       DCHECK(instruction_->IsCheckCast());
    319       arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
    320                                  instruction_,
    321                                  instruction_->GetDexPc(),
    322                                  this);
    323       CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
    324     }
    325 
    326     if (!is_fatal_) {
    327       RestoreLiveRegisters(codegen, locations);
    328       __ b(GetExitLabel());
    329     }
    330   }
    331 
    332   const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
    333 
    334   bool IsFatal() const OVERRIDE { return is_fatal_; }
    335 
    336  private:
    337   const bool is_fatal_;
    338 
    339   DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
    340 };
    341 
    342 class DeoptimizationSlowPathARM : public SlowPathCode {
    343  public:
    344   explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
    345     : SlowPathCode(instruction) {}
    346 
    347   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    348     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    349     __ Bind(GetEntryLabel());
    350     SaveLiveRegisters(codegen, instruction_->GetLocations());
    351     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
    352                                instruction_,
    353                                instruction_->GetDexPc(),
    354                                this);
    355     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
    356   }
    357 
    358   const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
    359 
    360  private:
    361   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
    362 };
    363 
    364 class ArraySetSlowPathARM : public SlowPathCode {
    365  public:
    366   explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {}
    367 
    368   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    369     LocationSummary* locations = instruction_->GetLocations();
    370     __ Bind(GetEntryLabel());
    371     SaveLiveRegisters(codegen, locations);
    372 
    373     InvokeRuntimeCallingConvention calling_convention;
    374     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
    375     parallel_move.AddMove(
    376         locations->InAt(0),
    377         Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
    378         Primitive::kPrimNot,
    379         nullptr);
    380     parallel_move.AddMove(
    381         locations->InAt(1),
    382         Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
    383         Primitive::kPrimInt,
    384         nullptr);
    385     parallel_move.AddMove(
    386         locations->InAt(2),
    387         Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
    388         Primitive::kPrimNot,
    389         nullptr);
    390     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
    391 
    392     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    393     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
    394                                instruction_,
    395                                instruction_->GetDexPc(),
    396                                this);
    397     CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
    398     RestoreLiveRegisters(codegen, locations);
    399     __ b(GetExitLabel());
    400   }
    401 
    402   const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
    403 
    404  private:
    405   DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
    406 };
    407 
    408 // Slow path marking an object during a read barrier.
    409 class ReadBarrierMarkSlowPathARM : public SlowPathCode {
    410  public:
    411   ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location out, Location obj)
    412       : SlowPathCode(instruction), out_(out), obj_(obj) {
    413     DCHECK(kEmitCompilerReadBarrier);
    414   }
    415 
    416   const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
    417 
    418   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    419     LocationSummary* locations = instruction_->GetLocations();
    420     Register reg_out = out_.AsRegister<Register>();
    421     DCHECK(locations->CanCall());
    422     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
    423     DCHECK(instruction_->IsInstanceFieldGet() ||
    424            instruction_->IsStaticFieldGet() ||
    425            instruction_->IsArrayGet() ||
    426            instruction_->IsLoadClass() ||
    427            instruction_->IsLoadString() ||
    428            instruction_->IsInstanceOf() ||
    429            instruction_->IsCheckCast())
    430         << "Unexpected instruction in read barrier marking slow path: "
    431         << instruction_->DebugName();
    432 
    433     __ Bind(GetEntryLabel());
    434     SaveLiveRegisters(codegen, locations);
    435 
    436     InvokeRuntimeCallingConvention calling_convention;
    437     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    438     arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
    439     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
    440                                instruction_,
    441                                instruction_->GetDexPc(),
    442                                this);
    443     CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
    444     arm_codegen->Move32(out_, Location::RegisterLocation(R0));
    445 
    446     RestoreLiveRegisters(codegen, locations);
    447     __ b(GetExitLabel());
    448   }
    449 
    450  private:
    451   const Location out_;
    452   const Location obj_;
    453 
    454   DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
    455 };
    456 
    457 // Slow path generating a read barrier for a heap reference.
    458 class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
    459  public:
    460   ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
    461                                          Location out,
    462                                          Location ref,
    463                                          Location obj,
    464                                          uint32_t offset,
    465                                          Location index)
    466       : SlowPathCode(instruction),
    467         out_(out),
    468         ref_(ref),
    469         obj_(obj),
    470         offset_(offset),
    471         index_(index) {
    472     DCHECK(kEmitCompilerReadBarrier);
    473     // If `obj` is equal to `out` or `ref`, it means the initial object
    474     // has been overwritten by (or after) the heap object reference load
    475     // to be instrumented, e.g.:
    476     //
    477     //   __ LoadFromOffset(kLoadWord, out, out, offset);
    478     //   codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
    479     //
    480     // In that case, we have lost the information about the original
    481     // object, and the emitted read barrier cannot work properly.
    482     DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
    483     DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
    484   }
    485 
    486   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    487     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    488     LocationSummary* locations = instruction_->GetLocations();
    489     Register reg_out = out_.AsRegister<Register>();
    490     DCHECK(locations->CanCall());
    491     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
    492     DCHECK(!instruction_->IsInvoke() ||
    493            (instruction_->IsInvokeStaticOrDirect() &&
    494             instruction_->GetLocations()->Intrinsified()))
    495         << "Unexpected instruction in read barrier for heap reference slow path: "
    496         << instruction_->DebugName();
    497 
    498     __ Bind(GetEntryLabel());
    499     SaveLiveRegisters(codegen, locations);
    500 
    501     // We may have to change the index's value, but as `index_` is a
    502     // constant member (like other "inputs" of this slow path),
    503     // introduce a copy of it, `index`.
    504     Location index = index_;
    505     if (index_.IsValid()) {
    506       // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
    507       if (instruction_->IsArrayGet()) {
    508         // Compute the actual memory offset and store it in `index`.
    509         Register index_reg = index_.AsRegister<Register>();
    510         DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
    511         if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
    512           // We are about to change the value of `index_reg` (see the
    513           // calls to art::arm::Thumb2Assembler::Lsl and
    514           // art::arm::Thumb2Assembler::AddConstant below), but it has
    515           // not been saved by the previous call to
    516           // art::SlowPathCode::SaveLiveRegisters, as it is a
    517           // callee-save register --
    518           // art::SlowPathCode::SaveLiveRegisters does not consider
    519           // callee-save registers, as it has been designed with the
    520           // assumption that callee-save registers are supposed to be
    521           // handled by the called function.  So, as a callee-save
    522           // register, `index_reg` _would_ eventually be saved onto
    523           // the stack, but it would be too late: we would have
    524           // changed its value earlier.  Therefore, we manually save
    525           // it here into another freely available register,
    526           // `free_reg`, chosen of course among the caller-save
    527           // registers (as a callee-save `free_reg` register would
    528           // exhibit the same problem).
    529           //
    530           // Note we could have requested a temporary register from
    531           // the register allocator instead; but we prefer not to, as
    532           // this is a slow path, and we know we can find a
    533           // caller-save register that is available.
    534           Register free_reg = FindAvailableCallerSaveRegister(codegen);
    535           __ Mov(free_reg, index_reg);
    536           index_reg = free_reg;
    537           index = Location::RegisterLocation(index_reg);
    538         } else {
    539           // The initial register stored in `index_` has already been
    540           // saved in the call to art::SlowPathCode::SaveLiveRegisters
    541           // (as it is not a callee-save register), so we can freely
    542           // use it.
    543         }
    544         // Shifting the index value contained in `index_reg` by the scale
    545         // factor (2) cannot overflow in practice, as the runtime is
    546         // unable to allocate object arrays with a size larger than
    547         // 2^26 - 1 (that is, 2^28 - 4 bytes).
    548         __ Lsl(index_reg, index_reg, TIMES_4);
    549         static_assert(
    550             sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
    551             "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
    552         __ AddConstant(index_reg, index_reg, offset_);
    553       } else {
    554         DCHECK(instruction_->IsInvoke());
    555         DCHECK(instruction_->GetLocations()->Intrinsified());
    556         DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
    557                (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
    558             << instruction_->AsInvoke()->GetIntrinsic();
    559         DCHECK_EQ(offset_, 0U);
    560         DCHECK(index_.IsRegisterPair());
    561         // UnsafeGet's offset location is a register pair, the low
    562         // part contains the correct offset.
    563         index = index_.ToLow();
    564       }
    565     }
    566 
    567     // We're moving two or three locations to locations that could
    568     // overlap, so we need a parallel move resolver.
    569     InvokeRuntimeCallingConvention calling_convention;
    570     HParallelMove parallel_move(codegen->GetGraph()->GetArena());
    571     parallel_move.AddMove(ref_,
    572                           Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
    573                           Primitive::kPrimNot,
    574                           nullptr);
    575     parallel_move.AddMove(obj_,
    576                           Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
    577                           Primitive::kPrimNot,
    578                           nullptr);
    579     if (index.IsValid()) {
    580       parallel_move.AddMove(index,
    581                             Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
    582                             Primitive::kPrimInt,
    583                             nullptr);
    584       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
    585     } else {
    586       codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
    587       __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
    588     }
    589     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
    590                                instruction_,
    591                                instruction_->GetDexPc(),
    592                                this);
    593     CheckEntrypointTypes<
    594         kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
    595     arm_codegen->Move32(out_, Location::RegisterLocation(R0));
    596 
    597     RestoreLiveRegisters(codegen, locations);
    598     __ b(GetExitLabel());
    599   }
    600 
    601   const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
    602 
    603  private:
    604   Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
    605     size_t ref = static_cast<int>(ref_.AsRegister<Register>());
    606     size_t obj = static_cast<int>(obj_.AsRegister<Register>());
    607     for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
    608       if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
    609         return static_cast<Register>(i);
    610       }
    611     }
    612     // We shall never fail to find a free caller-save register, as
    613     // there are more than two core caller-save registers on ARM
    614     // (meaning it is possible to find one which is different from
    615     // `ref` and `obj`).
    616     DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
    617     LOG(FATAL) << "Could not find a free caller-save register";
    618     UNREACHABLE();
    619   }
    620 
    621   const Location out_;
    622   const Location ref_;
    623   const Location obj_;
    624   const uint32_t offset_;
    625   // An additional location containing an index to an array.
    626   // Only used for HArrayGet and the UnsafeGetObject &
    627   // UnsafeGetObjectVolatile intrinsics.
    628   const Location index_;
    629 
    630   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
    631 };
    632 
    633 // Slow path generating a read barrier for a GC root.
    634 class ReadBarrierForRootSlowPathARM : public SlowPathCode {
    635  public:
    636   ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
    637       : SlowPathCode(instruction), out_(out), root_(root) {
    638     DCHECK(kEmitCompilerReadBarrier);
    639   }
    640 
    641   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
    642     LocationSummary* locations = instruction_->GetLocations();
    643     Register reg_out = out_.AsRegister<Register>();
    644     DCHECK(locations->CanCall());
    645     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
    646     DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
    647         << "Unexpected instruction in read barrier for GC root slow path: "
    648         << instruction_->DebugName();
    649 
    650     __ Bind(GetEntryLabel());
    651     SaveLiveRegisters(codegen, locations);
    652 
    653     InvokeRuntimeCallingConvention calling_convention;
    654     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
    655     arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
    656     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
    657                                instruction_,
    658                                instruction_->GetDexPc(),
    659                                this);
    660     CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
    661     arm_codegen->Move32(out_, Location::RegisterLocation(R0));
    662 
    663     RestoreLiveRegisters(codegen, locations);
    664     __ b(GetExitLabel());
    665   }
    666 
    667   const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
    668 
    669  private:
    670   const Location out_;
    671   const Location root_;
    672 
    673   DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
    674 };
    675 
    676 #undef __
    677 #define __ down_cast<ArmAssembler*>(GetAssembler())->
    678 
    679 inline Condition ARMCondition(IfCondition cond) {
    680   switch (cond) {
    681     case kCondEQ: return EQ;
    682     case kCondNE: return NE;
    683     case kCondLT: return LT;
    684     case kCondLE: return LE;
    685     case kCondGT: return GT;
    686     case kCondGE: return GE;
    687     case kCondB:  return LO;
    688     case kCondBE: return LS;
    689     case kCondA:  return HI;
    690     case kCondAE: return HS;
    691   }
    692   LOG(FATAL) << "Unreachable";
    693   UNREACHABLE();
    694 }
    695 
    696 // Maps signed condition to unsigned condition.
    697 inline Condition ARMUnsignedCondition(IfCondition cond) {
    698   switch (cond) {
    699     case kCondEQ: return EQ;
    700     case kCondNE: return NE;
    701     // Signed to unsigned.
    702     case kCondLT: return LO;
    703     case kCondLE: return LS;
    704     case kCondGT: return HI;
    705     case kCondGE: return HS;
    706     // Unsigned remain unchanged.
    707     case kCondB:  return LO;
    708     case kCondBE: return LS;
    709     case kCondA:  return HI;
    710     case kCondAE: return HS;
    711   }
    712   LOG(FATAL) << "Unreachable";
    713   UNREACHABLE();
    714 }
    715 
    716 inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
    717   // The ARM condition codes can express all the necessary branches, see the
    718   // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
    719   // There is no dex instruction or HIR that would need the missing conditions
    720   // "equal or unordered" or "not equal".
    721   switch (cond) {
    722     case kCondEQ: return EQ;
    723     case kCondNE: return NE /* unordered */;
    724     case kCondLT: return gt_bias ? CC : LT /* unordered */;
    725     case kCondLE: return gt_bias ? LS : LE /* unordered */;
    726     case kCondGT: return gt_bias ? HI /* unordered */ : GT;
    727     case kCondGE: return gt_bias ? CS /* unordered */ : GE;
    728     default:
    729       LOG(FATAL) << "UNREACHABLE";
    730       UNREACHABLE();
    731   }
    732 }
    733 
    734 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
    735   stream << Register(reg);
    736 }
    737 
    738 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
    739   stream << SRegister(reg);
    740 }
    741 
    742 size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
    743   __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
    744   return kArmWordSize;
    745 }
    746 
    747 size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
    748   __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
    749   return kArmWordSize;
    750 }
    751 
    752 size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
    753   __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
    754   return kArmWordSize;
    755 }
    756 
    757 size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
    758   __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
    759   return kArmWordSize;
    760 }
    761 
    762 CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
    763                                    const ArmInstructionSetFeatures& isa_features,
    764                                    const CompilerOptions& compiler_options,
    765                                    OptimizingCompilerStats* stats)
    766     : CodeGenerator(graph,
    767                     kNumberOfCoreRegisters,
    768                     kNumberOfSRegisters,
    769                     kNumberOfRegisterPairs,
    770                     ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
    771                                         arraysize(kCoreCalleeSaves)),
    772                     ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
    773                                         arraysize(kFpuCalleeSaves)),
    774                     compiler_options,
    775                     stats),
    776       block_labels_(nullptr),
    777       location_builder_(graph, this),
    778       instruction_visitor_(graph, this),
    779       move_resolver_(graph->GetArena(), this),
    780       assembler_(graph->GetArena()),
    781       isa_features_(isa_features),
    782       uint32_literals_(std::less<uint32_t>(),
    783                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    784       method_patches_(MethodReferenceComparator(),
    785                       graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    786       call_patches_(MethodReferenceComparator(),
    787                     graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    788       relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    789       pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    790       boot_image_string_patches_(StringReferenceValueComparator(),
    791                                  graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    792       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
    793       boot_image_address_patches_(std::less<uint32_t>(),
    794                                   graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
    795   // Always save the LR register to mimic Quick.
    796   AddAllocatedRegister(Location::RegisterLocation(LR));
    797 }
    798 
    799 void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
    800   // Ensure that we fix up branches and literal loads and emit the literal pool.
    801   __ FinalizeCode();
    802 
    803   // Adjust native pc offsets in stack maps.
    804   for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
    805     uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
    806     uint32_t new_position = __ GetAdjustedPosition(old_position);
    807     stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
    808   }
    809   // Adjust pc offsets for the disassembly information.
    810   if (disasm_info_ != nullptr) {
    811     GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
    812     frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
    813     frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
    814     for (auto& it : *disasm_info_->GetInstructionIntervals()) {
    815       it.second.start = __ GetAdjustedPosition(it.second.start);
    816       it.second.end = __ GetAdjustedPosition(it.second.end);
    817     }
    818     for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
    819       it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
    820       it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
    821     }
    822   }
    823 
    824   CodeGenerator::Finalize(allocator);
    825 }
    826 
    827 void CodeGeneratorARM::SetupBlockedRegisters() const {
    828   // Don't allocate the dalvik style register pair passing.
    829   blocked_register_pairs_[R1_R2] = true;
    830 
    831   // Stack register, LR and PC are always reserved.
    832   blocked_core_registers_[SP] = true;
    833   blocked_core_registers_[LR] = true;
    834   blocked_core_registers_[PC] = true;
    835 
    836   // Reserve thread register.
    837   blocked_core_registers_[TR] = true;
    838 
    839   // Reserve temp register.
    840   blocked_core_registers_[IP] = true;
    841 
    842   if (GetGraph()->IsDebuggable()) {
    843     // Stubs do not save callee-save floating point registers. If the graph
    844     // is debuggable, we need to deal with these registers differently. For
    845     // now, just block them.
    846     for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
    847       blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
    848     }
    849   }
    850 
    851   UpdateBlockedPairRegisters();
    852 }
    853 
    854 void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
    855   for (int i = 0; i < kNumberOfRegisterPairs; i++) {
    856     ArmManagedRegister current =
    857         ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
    858     if (blocked_core_registers_[current.AsRegisterPairLow()]
    859         || blocked_core_registers_[current.AsRegisterPairHigh()]) {
    860       blocked_register_pairs_[i] = true;
    861     }
    862   }
    863 }
    864 
    865 InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
    866       : InstructionCodeGenerator(graph, codegen),
    867         assembler_(codegen->GetAssembler()),
    868         codegen_(codegen) {}
    869 
    870 void CodeGeneratorARM::ComputeSpillMask() {
    871   core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
    872   DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
    873   // There is no easy instruction to restore just the PC on thumb2. We spill and
    874   // restore another arbitrary register.
    875   core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
    876   fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
    877   // We use vpush and vpop for saving and restoring floating point registers, which take
    878   // a SRegister and the number of registers to save/restore after that SRegister. We
    879   // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
    880   // but in the range.
    881   if (fpu_spill_mask_ != 0) {
    882     uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
    883     uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
    884     for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
    885       fpu_spill_mask_ |= (1 << i);
    886     }
    887   }
    888 }
    889 
    890 static dwarf::Reg DWARFReg(Register reg) {
    891   return dwarf::Reg::ArmCore(static_cast<int>(reg));
    892 }
    893 
    894 static dwarf::Reg DWARFReg(SRegister reg) {
    895   return dwarf::Reg::ArmFp(static_cast<int>(reg));
    896 }
    897 
    898 void CodeGeneratorARM::GenerateFrameEntry() {
    899   bool skip_overflow_check =
    900       IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
    901   DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
    902   __ Bind(&frame_entry_label_);
    903 
    904   if (HasEmptyFrame()) {
    905     return;
    906   }
    907 
    908   if (!skip_overflow_check) {
    909     __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
    910     __ LoadFromOffset(kLoadWord, IP, IP, 0);
    911     RecordPcInfo(nullptr, 0);
    912   }
    913 
    914   __ PushList(core_spill_mask_);
    915   __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
    916   __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
    917   if (fpu_spill_mask_ != 0) {
    918     SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
    919     __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
    920     __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
    921     __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
    922   }
    923   int adjust = GetFrameSize() - FrameEntrySpillSize();
    924   __ AddConstant(SP, -adjust);
    925   __ cfi().AdjustCFAOffset(adjust);
    926   __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
    927 }
    928 
    929 void CodeGeneratorARM::GenerateFrameExit() {
    930   if (HasEmptyFrame()) {
    931     __ bx(LR);
    932     return;
    933   }
    934   __ cfi().RememberState();
    935   int adjust = GetFrameSize() - FrameEntrySpillSize();
    936   __ AddConstant(SP, adjust);
    937   __ cfi().AdjustCFAOffset(-adjust);
    938   if (fpu_spill_mask_ != 0) {
    939     SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
    940     __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
    941     __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
    942     __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
    943   }
    944   // Pop LR into PC to return.
    945   DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
    946   uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
    947   __ PopList(pop_mask);
    948   __ cfi().RestoreState();
    949   __ cfi().DefCFAOffset(GetFrameSize());
    950 }
    951 
    952 void CodeGeneratorARM::Bind(HBasicBlock* block) {
    953   Label* label = GetLabelOf(block);
    954   __ BindTrackedLabel(label);
    955 }
    956 
    957 Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
    958   switch (type) {
    959     case Primitive::kPrimBoolean:
    960     case Primitive::kPrimByte:
    961     case Primitive::kPrimChar:
    962     case Primitive::kPrimShort:
    963     case Primitive::kPrimInt:
    964     case Primitive::kPrimNot: {
    965       uint32_t index = gp_index_++;
    966       uint32_t stack_index = stack_index_++;
    967       if (index < calling_convention.GetNumberOfRegisters()) {
    968         return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
    969       } else {
    970         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
    971       }
    972     }
    973 
    974     case Primitive::kPrimLong: {
    975       uint32_t index = gp_index_;
    976       uint32_t stack_index = stack_index_;
    977       gp_index_ += 2;
    978       stack_index_ += 2;
    979       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
    980         if (calling_convention.GetRegisterAt(index) == R1) {
    981           // Skip R1, and use R2_R3 instead.
    982           gp_index_++;
    983           index++;
    984         }
    985       }
    986       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
    987         DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
    988                   calling_convention.GetRegisterAt(index + 1));
    989 
    990         return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
    991                                               calling_convention.GetRegisterAt(index + 1));
    992       } else {
    993         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
    994       }
    995     }
    996 
    997     case Primitive::kPrimFloat: {
    998       uint32_t stack_index = stack_index_++;
    999       if (float_index_ % 2 == 0) {
   1000         float_index_ = std::max(double_index_, float_index_);
   1001       }
   1002       if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
   1003         return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
   1004       } else {
   1005         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
   1006       }
   1007     }
   1008 
   1009     case Primitive::kPrimDouble: {
   1010       double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
   1011       uint32_t stack_index = stack_index_;
   1012       stack_index_ += 2;
   1013       if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
   1014         uint32_t index = double_index_;
   1015         double_index_ += 2;
   1016         Location result = Location::FpuRegisterPairLocation(
   1017           calling_convention.GetFpuRegisterAt(index),
   1018           calling_convention.GetFpuRegisterAt(index + 1));
   1019         DCHECK(ExpectedPairLayout(result));
   1020         return result;
   1021       } else {
   1022         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
   1023       }
   1024     }
   1025 
   1026     case Primitive::kPrimVoid:
   1027       LOG(FATAL) << "Unexpected parameter type " << type;
   1028       break;
   1029   }
   1030   return Location::NoLocation();
   1031 }
   1032 
   1033 Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
   1034   switch (type) {
   1035     case Primitive::kPrimBoolean:
   1036     case Primitive::kPrimByte:
   1037     case Primitive::kPrimChar:
   1038     case Primitive::kPrimShort:
   1039     case Primitive::kPrimInt:
   1040     case Primitive::kPrimNot: {
   1041       return Location::RegisterLocation(R0);
   1042     }
   1043 
   1044     case Primitive::kPrimFloat: {
   1045       return Location::FpuRegisterLocation(S0);
   1046     }
   1047 
   1048     case Primitive::kPrimLong: {
   1049       return Location::RegisterPairLocation(R0, R1);
   1050     }
   1051 
   1052     case Primitive::kPrimDouble: {
   1053       return Location::FpuRegisterPairLocation(S0, S1);
   1054     }
   1055 
   1056     case Primitive::kPrimVoid:
   1057       return Location::NoLocation();
   1058   }
   1059 
   1060   UNREACHABLE();
   1061 }
   1062 
   1063 Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
   1064   return Location::RegisterLocation(kMethodRegisterArgument);
   1065 }
   1066 
   1067 void CodeGeneratorARM::Move32(Location destination, Location source) {
   1068   if (source.Equals(destination)) {
   1069     return;
   1070   }
   1071   if (destination.IsRegister()) {
   1072     if (source.IsRegister()) {
   1073       __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
   1074     } else if (source.IsFpuRegister()) {
   1075       __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
   1076     } else {
   1077       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
   1078     }
   1079   } else if (destination.IsFpuRegister()) {
   1080     if (source.IsRegister()) {
   1081       __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
   1082     } else if (source.IsFpuRegister()) {
   1083       __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
   1084     } else {
   1085       __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
   1086     }
   1087   } else {
   1088     DCHECK(destination.IsStackSlot()) << destination;
   1089     if (source.IsRegister()) {
   1090       __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
   1091     } else if (source.IsFpuRegister()) {
   1092       __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
   1093     } else {
   1094       DCHECK(source.IsStackSlot()) << source;
   1095       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
   1096       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   1097     }
   1098   }
   1099 }
   1100 
   1101 void CodeGeneratorARM::Move64(Location destination, Location source) {
   1102   if (source.Equals(destination)) {
   1103     return;
   1104   }
   1105   if (destination.IsRegisterPair()) {
   1106     if (source.IsRegisterPair()) {
   1107       EmitParallelMoves(
   1108           Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
   1109           Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
   1110           Primitive::kPrimInt,
   1111           Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
   1112           Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
   1113           Primitive::kPrimInt);
   1114     } else if (source.IsFpuRegister()) {
   1115       UNIMPLEMENTED(FATAL);
   1116     } else if (source.IsFpuRegisterPair()) {
   1117       __ vmovrrd(destination.AsRegisterPairLow<Register>(),
   1118                  destination.AsRegisterPairHigh<Register>(),
   1119                  FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
   1120     } else {
   1121       DCHECK(source.IsDoubleStackSlot());
   1122       DCHECK(ExpectedPairLayout(destination));
   1123       __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
   1124                         SP, source.GetStackIndex());
   1125     }
   1126   } else if (destination.IsFpuRegisterPair()) {
   1127     if (source.IsDoubleStackSlot()) {
   1128       __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   1129                          SP,
   1130                          source.GetStackIndex());
   1131     } else if (source.IsRegisterPair()) {
   1132       __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   1133                  source.AsRegisterPairLow<Register>(),
   1134                  source.AsRegisterPairHigh<Register>());
   1135     } else {
   1136       UNIMPLEMENTED(FATAL);
   1137     }
   1138   } else {
   1139     DCHECK(destination.IsDoubleStackSlot());
   1140     if (source.IsRegisterPair()) {
   1141       // No conflict possible, so just do the moves.
   1142       if (source.AsRegisterPairLow<Register>() == R1) {
   1143         DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
   1144         __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
   1145         __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
   1146       } else {
   1147         __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
   1148                          SP, destination.GetStackIndex());
   1149       }
   1150     } else if (source.IsFpuRegisterPair()) {
   1151       __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
   1152                         SP,
   1153                         destination.GetStackIndex());
   1154     } else {
   1155       DCHECK(source.IsDoubleStackSlot());
   1156       EmitParallelMoves(
   1157           Location::StackSlot(source.GetStackIndex()),
   1158           Location::StackSlot(destination.GetStackIndex()),
   1159           Primitive::kPrimInt,
   1160           Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
   1161           Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
   1162           Primitive::kPrimInt);
   1163     }
   1164   }
   1165 }
   1166 
   1167 void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
   1168   DCHECK(location.IsRegister());
   1169   __ LoadImmediate(location.AsRegister<Register>(), value);
   1170 }
   1171 
   1172 void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
   1173   HParallelMove move(GetGraph()->GetArena());
   1174   move.AddMove(src, dst, dst_type, nullptr);
   1175   GetMoveResolver()->EmitNativeCode(&move);
   1176 }
   1177 
   1178 void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
   1179   if (location.IsRegister()) {
   1180     locations->AddTemp(location);
   1181   } else if (location.IsRegisterPair()) {
   1182     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
   1183     locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
   1184   } else {
   1185     UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
   1186   }
   1187 }
   1188 
   1189 void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
   1190                                      HInstruction* instruction,
   1191                                      uint32_t dex_pc,
   1192                                      SlowPathCode* slow_path) {
   1193   InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
   1194                 instruction,
   1195                 dex_pc,
   1196                 slow_path);
   1197 }
   1198 
   1199 void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
   1200                                      HInstruction* instruction,
   1201                                      uint32_t dex_pc,
   1202                                      SlowPathCode* slow_path) {
   1203   ValidateInvokeRuntime(instruction, slow_path);
   1204   __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
   1205   __ blx(LR);
   1206   RecordPcInfo(instruction, dex_pc, slow_path);
   1207 }
   1208 
   1209 void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   1210   DCHECK(!successor->IsExitBlock());
   1211 
   1212   HBasicBlock* block = got->GetBlock();
   1213   HInstruction* previous = got->GetPrevious();
   1214 
   1215   HLoopInformation* info = block->GetLoopInformation();
   1216   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
   1217     codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
   1218     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
   1219     return;
   1220   }
   1221 
   1222   if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
   1223     GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
   1224   }
   1225   if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
   1226     __ b(codegen_->GetLabelOf(successor));
   1227   }
   1228 }
   1229 
   1230 void LocationsBuilderARM::VisitGoto(HGoto* got) {
   1231   got->SetLocations(nullptr);
   1232 }
   1233 
   1234 void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
   1235   HandleGoto(got, got->GetSuccessor());
   1236 }
   1237 
   1238 void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
   1239   try_boundary->SetLocations(nullptr);
   1240 }
   1241 
   1242 void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
   1243   HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
   1244   if (!successor->IsExitBlock()) {
   1245     HandleGoto(try_boundary, successor);
   1246   }
   1247 }
   1248 
   1249 void LocationsBuilderARM::VisitExit(HExit* exit) {
   1250   exit->SetLocations(nullptr);
   1251 }
   1252 
   1253 void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
   1254 }
   1255 
   1256 void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
   1257                                                   Label* true_label,
   1258                                                   Label* false_label ATTRIBUTE_UNUSED) {
   1259   __ vmstat();  // transfer FP status register to ARM APSR.
   1260   __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
   1261 }
   1262 
   1263 void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
   1264                                                                Label* true_label,
   1265                                                                Label* false_label) {
   1266   LocationSummary* locations = cond->GetLocations();
   1267   Location left = locations->InAt(0);
   1268   Location right = locations->InAt(1);
   1269   IfCondition if_cond = cond->GetCondition();
   1270 
   1271   Register left_high = left.AsRegisterPairHigh<Register>();
   1272   Register left_low = left.AsRegisterPairLow<Register>();
   1273   IfCondition true_high_cond = if_cond;
   1274   IfCondition false_high_cond = cond->GetOppositeCondition();
   1275   Condition final_condition = ARMUnsignedCondition(if_cond);  // unsigned on lower part
   1276 
   1277   // Set the conditions for the test, remembering that == needs to be
   1278   // decided using the low words.
   1279   // TODO: consider avoiding jumps with temporary and CMP low+SBC high
   1280   switch (if_cond) {
   1281     case kCondEQ:
   1282     case kCondNE:
   1283       // Nothing to do.
   1284       break;
   1285     case kCondLT:
   1286       false_high_cond = kCondGT;
   1287       break;
   1288     case kCondLE:
   1289       true_high_cond = kCondLT;
   1290       break;
   1291     case kCondGT:
   1292       false_high_cond = kCondLT;
   1293       break;
   1294     case kCondGE:
   1295       true_high_cond = kCondGT;
   1296       break;
   1297     case kCondB:
   1298       false_high_cond = kCondA;
   1299       break;
   1300     case kCondBE:
   1301       true_high_cond = kCondB;
   1302       break;
   1303     case kCondA:
   1304       false_high_cond = kCondB;
   1305       break;
   1306     case kCondAE:
   1307       true_high_cond = kCondA;
   1308       break;
   1309   }
   1310   if (right.IsConstant()) {
   1311     int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
   1312     int32_t val_low = Low32Bits(value);
   1313     int32_t val_high = High32Bits(value);
   1314 
   1315     __ CmpConstant(left_high, val_high);
   1316     if (if_cond == kCondNE) {
   1317       __ b(true_label, ARMCondition(true_high_cond));
   1318     } else if (if_cond == kCondEQ) {
   1319       __ b(false_label, ARMCondition(false_high_cond));
   1320     } else {
   1321       __ b(true_label, ARMCondition(true_high_cond));
   1322       __ b(false_label, ARMCondition(false_high_cond));
   1323     }
   1324     // Must be equal high, so compare the lows.
   1325     __ CmpConstant(left_low, val_low);
   1326   } else {
   1327     Register right_high = right.AsRegisterPairHigh<Register>();
   1328     Register right_low = right.AsRegisterPairLow<Register>();
   1329 
   1330     __ cmp(left_high, ShifterOperand(right_high));
   1331     if (if_cond == kCondNE) {
   1332       __ b(true_label, ARMCondition(true_high_cond));
   1333     } else if (if_cond == kCondEQ) {
   1334       __ b(false_label, ARMCondition(false_high_cond));
   1335     } else {
   1336       __ b(true_label, ARMCondition(true_high_cond));
   1337       __ b(false_label, ARMCondition(false_high_cond));
   1338     }
   1339     // Must be equal high, so compare the lows.
   1340     __ cmp(left_low, ShifterOperand(right_low));
   1341   }
   1342   // The last comparison might be unsigned.
   1343   // TODO: optimize cases where this is always true/false
   1344   __ b(true_label, final_condition);
   1345 }
   1346 
   1347 void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
   1348                                                                Label* true_target_in,
   1349                                                                Label* false_target_in) {
   1350   // Generated branching requires both targets to be explicit. If either of the
   1351   // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
   1352   Label fallthrough_target;
   1353   Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
   1354   Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
   1355 
   1356   LocationSummary* locations = condition->GetLocations();
   1357   Location left = locations->InAt(0);
   1358   Location right = locations->InAt(1);
   1359 
   1360   Primitive::Type type = condition->InputAt(0)->GetType();
   1361   switch (type) {
   1362     case Primitive::kPrimLong:
   1363       GenerateLongComparesAndJumps(condition, true_target, false_target);
   1364       break;
   1365     case Primitive::kPrimFloat:
   1366       __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
   1367       GenerateFPJumps(condition, true_target, false_target);
   1368       break;
   1369     case Primitive::kPrimDouble:
   1370       __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
   1371                FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
   1372       GenerateFPJumps(condition, true_target, false_target);
   1373       break;
   1374     default:
   1375       LOG(FATAL) << "Unexpected compare type " << type;
   1376   }
   1377 
   1378   if (false_target != &fallthrough_target) {
   1379     __ b(false_target);
   1380   }
   1381 
   1382   if (fallthrough_target.IsLinked()) {
   1383     __ Bind(&fallthrough_target);
   1384   }
   1385 }
   1386 
   1387 void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
   1388                                                         size_t condition_input_index,
   1389                                                         Label* true_target,
   1390                                                         Label* false_target) {
   1391   HInstruction* cond = instruction->InputAt(condition_input_index);
   1392 
   1393   if (true_target == nullptr && false_target == nullptr) {
   1394     // Nothing to do. The code always falls through.
   1395     return;
   1396   } else if (cond->IsIntConstant()) {
   1397     // Constant condition, statically compared against "true" (integer value 1).
   1398     if (cond->AsIntConstant()->IsTrue()) {
   1399       if (true_target != nullptr) {
   1400         __ b(true_target);
   1401       }
   1402     } else {
   1403       DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
   1404       if (false_target != nullptr) {
   1405         __ b(false_target);
   1406       }
   1407     }
   1408     return;
   1409   }
   1410 
   1411   // The following code generates these patterns:
   1412   //  (1) true_target == nullptr && false_target != nullptr
   1413   //        - opposite condition true => branch to false_target
   1414   //  (2) true_target != nullptr && false_target == nullptr
   1415   //        - condition true => branch to true_target
   1416   //  (3) true_target != nullptr && false_target != nullptr
   1417   //        - condition true => branch to true_target
   1418   //        - branch to false_target
   1419   if (IsBooleanValueOrMaterializedCondition(cond)) {
   1420     // Condition has been materialized, compare the output to 0.
   1421     Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
   1422     DCHECK(cond_val.IsRegister());
   1423     if (true_target == nullptr) {
   1424       __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
   1425     } else {
   1426       __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
   1427     }
   1428   } else {
   1429     // Condition has not been materialized. Use its inputs as the comparison and
   1430     // its condition as the branch condition.
   1431     HCondition* condition = cond->AsCondition();
   1432 
   1433     // If this is a long or FP comparison that has been folded into
   1434     // the HCondition, generate the comparison directly.
   1435     Primitive::Type type = condition->InputAt(0)->GetType();
   1436     if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
   1437       GenerateCompareTestAndBranch(condition, true_target, false_target);
   1438       return;
   1439     }
   1440 
   1441     LocationSummary* locations = cond->GetLocations();
   1442     DCHECK(locations->InAt(0).IsRegister());
   1443     Register left = locations->InAt(0).AsRegister<Register>();
   1444     Location right = locations->InAt(1);
   1445     if (right.IsRegister()) {
   1446       __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
   1447     } else {
   1448       DCHECK(right.IsConstant());
   1449       __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
   1450     }
   1451     if (true_target == nullptr) {
   1452       __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
   1453     } else {
   1454       __ b(true_target, ARMCondition(condition->GetCondition()));
   1455     }
   1456   }
   1457 
   1458   // If neither branch falls through (case 3), the conditional branch to `true_target`
   1459   // was already emitted (case 2) and we need to emit a jump to `false_target`.
   1460   if (true_target != nullptr && false_target != nullptr) {
   1461     __ b(false_target);
   1462   }
   1463 }
   1464 
   1465 void LocationsBuilderARM::VisitIf(HIf* if_instr) {
   1466   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
   1467   if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
   1468     locations->SetInAt(0, Location::RequiresRegister());
   1469   }
   1470 }
   1471 
   1472 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
   1473   HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
   1474   HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
   1475   Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
   1476       nullptr : codegen_->GetLabelOf(true_successor);
   1477   Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
   1478       nullptr : codegen_->GetLabelOf(false_successor);
   1479   GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
   1480 }
   1481 
   1482 void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
   1483   LocationSummary* locations = new (GetGraph()->GetArena())
   1484       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
   1485   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
   1486     locations->SetInAt(0, Location::RequiresRegister());
   1487   }
   1488 }
   1489 
   1490 void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
   1491   SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
   1492   GenerateTestAndBranch(deoptimize,
   1493                         /* condition_input_index */ 0,
   1494                         slow_path->GetEntryLabel(),
   1495                         /* false_target */ nullptr);
   1496 }
   1497 
   1498 void LocationsBuilderARM::VisitSelect(HSelect* select) {
   1499   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
   1500   if (Primitive::IsFloatingPointType(select->GetType())) {
   1501     locations->SetInAt(0, Location::RequiresFpuRegister());
   1502     locations->SetInAt(1, Location::RequiresFpuRegister());
   1503   } else {
   1504     locations->SetInAt(0, Location::RequiresRegister());
   1505     locations->SetInAt(1, Location::RequiresRegister());
   1506   }
   1507   if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
   1508     locations->SetInAt(2, Location::RequiresRegister());
   1509   }
   1510   locations->SetOut(Location::SameAsFirstInput());
   1511 }
   1512 
   1513 void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
   1514   LocationSummary* locations = select->GetLocations();
   1515   Label false_target;
   1516   GenerateTestAndBranch(select,
   1517                         /* condition_input_index */ 2,
   1518                         /* true_target */ nullptr,
   1519                         &false_target);
   1520   codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
   1521   __ Bind(&false_target);
   1522 }
   1523 
   1524 void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
   1525   new (GetGraph()->GetArena()) LocationSummary(info);
   1526 }
   1527 
   1528 void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
   1529   // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
   1530 }
   1531 
   1532 void CodeGeneratorARM::GenerateNop() {
   1533   __ nop();
   1534 }
   1535 
   1536 void LocationsBuilderARM::HandleCondition(HCondition* cond) {
   1537   LocationSummary* locations =
   1538       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   1539   // Handle the long/FP comparisons made in instruction simplification.
   1540   switch (cond->InputAt(0)->GetType()) {
   1541     case Primitive::kPrimLong:
   1542       locations->SetInAt(0, Location::RequiresRegister());
   1543       locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
   1544       if (!cond->IsEmittedAtUseSite()) {
   1545         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   1546       }
   1547       break;
   1548 
   1549     case Primitive::kPrimFloat:
   1550     case Primitive::kPrimDouble:
   1551       locations->SetInAt(0, Location::RequiresFpuRegister());
   1552       locations->SetInAt(1, Location::RequiresFpuRegister());
   1553       if (!cond->IsEmittedAtUseSite()) {
   1554         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   1555       }
   1556       break;
   1557 
   1558     default:
   1559       locations->SetInAt(0, Location::RequiresRegister());
   1560       locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
   1561       if (!cond->IsEmittedAtUseSite()) {
   1562         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   1563       }
   1564   }
   1565 }
   1566 
   1567 void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
   1568   if (cond->IsEmittedAtUseSite()) {
   1569     return;
   1570   }
   1571 
   1572   LocationSummary* locations = cond->GetLocations();
   1573   Location left = locations->InAt(0);
   1574   Location right = locations->InAt(1);
   1575   Register out = locations->Out().AsRegister<Register>();
   1576   Label true_label, false_label;
   1577 
   1578   switch (cond->InputAt(0)->GetType()) {
   1579     default: {
   1580       // Integer case.
   1581       if (right.IsRegister()) {
   1582         __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
   1583       } else {
   1584         DCHECK(right.IsConstant());
   1585         __ CmpConstant(left.AsRegister<Register>(),
   1586                        CodeGenerator::GetInt32ValueOf(right.GetConstant()));
   1587       }
   1588       __ it(ARMCondition(cond->GetCondition()), kItElse);
   1589       __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
   1590              ARMCondition(cond->GetCondition()));
   1591       __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
   1592              ARMCondition(cond->GetOppositeCondition()));
   1593       return;
   1594     }
   1595     case Primitive::kPrimLong:
   1596       GenerateLongComparesAndJumps(cond, &true_label, &false_label);
   1597       break;
   1598     case Primitive::kPrimFloat:
   1599       __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
   1600       GenerateFPJumps(cond, &true_label, &false_label);
   1601       break;
   1602     case Primitive::kPrimDouble:
   1603       __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
   1604                FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
   1605       GenerateFPJumps(cond, &true_label, &false_label);
   1606       break;
   1607   }
   1608 
   1609   // Convert the jumps into the result.
   1610   Label done_label;
   1611 
   1612   // False case: result = 0.
   1613   __ Bind(&false_label);
   1614   __ LoadImmediate(out, 0);
   1615   __ b(&done_label);
   1616 
   1617   // True case: result = 1.
   1618   __ Bind(&true_label);
   1619   __ LoadImmediate(out, 1);
   1620   __ Bind(&done_label);
   1621 }
   1622 
   1623 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
   1624   HandleCondition(comp);
   1625 }
   1626 
   1627 void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
   1628   HandleCondition(comp);
   1629 }
   1630 
   1631 void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
   1632   HandleCondition(comp);
   1633 }
   1634 
   1635 void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
   1636   HandleCondition(comp);
   1637 }
   1638 
   1639 void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
   1640   HandleCondition(comp);
   1641 }
   1642 
   1643 void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
   1644   HandleCondition(comp);
   1645 }
   1646 
   1647 void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
   1648   HandleCondition(comp);
   1649 }
   1650 
   1651 void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
   1652   HandleCondition(comp);
   1653 }
   1654 
   1655 void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
   1656   HandleCondition(comp);
   1657 }
   1658 
   1659 void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
   1660   HandleCondition(comp);
   1661 }
   1662 
   1663 void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
   1664   HandleCondition(comp);
   1665 }
   1666 
   1667 void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
   1668   HandleCondition(comp);
   1669 }
   1670 
   1671 void LocationsBuilderARM::VisitBelow(HBelow* comp) {
   1672   HandleCondition(comp);
   1673 }
   1674 
   1675 void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
   1676   HandleCondition(comp);
   1677 }
   1678 
   1679 void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
   1680   HandleCondition(comp);
   1681 }
   1682 
   1683 void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
   1684   HandleCondition(comp);
   1685 }
   1686 
   1687 void LocationsBuilderARM::VisitAbove(HAbove* comp) {
   1688   HandleCondition(comp);
   1689 }
   1690 
   1691 void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
   1692   HandleCondition(comp);
   1693 }
   1694 
   1695 void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
   1696   HandleCondition(comp);
   1697 }
   1698 
   1699 void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
   1700   HandleCondition(comp);
   1701 }
   1702 
   1703 void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
   1704   LocationSummary* locations =
   1705       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
   1706   locations->SetOut(Location::ConstantLocation(constant));
   1707 }
   1708 
   1709 void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
   1710   // Will be generated at use site.
   1711 }
   1712 
   1713 void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
   1714   LocationSummary* locations =
   1715       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
   1716   locations->SetOut(Location::ConstantLocation(constant));
   1717 }
   1718 
   1719 void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
   1720   // Will be generated at use site.
   1721 }
   1722 
   1723 void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
   1724   LocationSummary* locations =
   1725       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
   1726   locations->SetOut(Location::ConstantLocation(constant));
   1727 }
   1728 
   1729 void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
   1730   // Will be generated at use site.
   1731 }
   1732 
   1733 void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
   1734   LocationSummary* locations =
   1735       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
   1736   locations->SetOut(Location::ConstantLocation(constant));
   1737 }
   1738 
   1739 void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
   1740   // Will be generated at use site.
   1741 }
   1742 
   1743 void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
   1744   LocationSummary* locations =
   1745       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
   1746   locations->SetOut(Location::ConstantLocation(constant));
   1747 }
   1748 
   1749 void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
   1750   // Will be generated at use site.
   1751 }
   1752 
   1753 void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
   1754   memory_barrier->SetLocations(nullptr);
   1755 }
   1756 
   1757 void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
   1758   codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
   1759 }
   1760 
   1761 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
   1762   ret->SetLocations(nullptr);
   1763 }
   1764 
   1765 void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
   1766   codegen_->GenerateFrameExit();
   1767 }
   1768 
   1769 void LocationsBuilderARM::VisitReturn(HReturn* ret) {
   1770   LocationSummary* locations =
   1771       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
   1772   locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
   1773 }
   1774 
   1775 void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
   1776   codegen_->GenerateFrameExit();
   1777 }
   1778 
   1779 void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
   1780   // The trampoline uses the same calling convention as dex calling conventions,
   1781   // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
   1782   // the method_idx.
   1783   HandleInvoke(invoke);
   1784 }
   1785 
   1786 void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
   1787   codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
   1788 }
   1789 
   1790 void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   1791   // Explicit clinit checks triggered by static invokes must have been pruned by
   1792   // art::PrepareForRegisterAllocation.
   1793   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
   1794 
   1795   IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
   1796                                          codegen_->GetAssembler(),
   1797                                          codegen_->GetInstructionSetFeatures());
   1798   if (intrinsic.TryDispatch(invoke)) {
   1799     if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
   1800       invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
   1801     }
   1802     return;
   1803   }
   1804 
   1805   HandleInvoke(invoke);
   1806 
   1807   // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
   1808   if (invoke->HasPcRelativeDexCache()) {
   1809     invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
   1810   }
   1811 }
   1812 
   1813 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
   1814   if (invoke->GetLocations()->Intrinsified()) {
   1815     IntrinsicCodeGeneratorARM intrinsic(codegen);
   1816     intrinsic.Dispatch(invoke);
   1817     return true;
   1818   }
   1819   return false;
   1820 }
   1821 
   1822 void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   1823   // Explicit clinit checks triggered by static invokes must have been pruned by
   1824   // art::PrepareForRegisterAllocation.
   1825   DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
   1826 
   1827   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
   1828     return;
   1829   }
   1830 
   1831   LocationSummary* locations = invoke->GetLocations();
   1832   codegen_->GenerateStaticOrDirectCall(
   1833       invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
   1834   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
   1835 }
   1836 
   1837 void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
   1838   InvokeDexCallingConventionVisitorARM calling_convention_visitor;
   1839   CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
   1840 }
   1841 
   1842 void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   1843   IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
   1844                                          codegen_->GetAssembler(),
   1845                                          codegen_->GetInstructionSetFeatures());
   1846   if (intrinsic.TryDispatch(invoke)) {
   1847     return;
   1848   }
   1849 
   1850   HandleInvoke(invoke);
   1851 }
   1852 
   1853 void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   1854   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
   1855     return;
   1856   }
   1857 
   1858   codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
   1859   DCHECK(!codegen_->IsLeafMethod());
   1860   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
   1861 }
   1862 
   1863 void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
   1864   HandleInvoke(invoke);
   1865   // Add the hidden argument.
   1866   invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
   1867 }
   1868 
   1869 void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
   1870   // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
   1871   LocationSummary* locations = invoke->GetLocations();
   1872   Register temp = locations->GetTemp(0).AsRegister<Register>();
   1873   Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
   1874   Location receiver = locations->InAt(0);
   1875   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   1876 
   1877   // Set the hidden argument. This is safe to do this here, as R12
   1878   // won't be modified thereafter, before the `blx` (call) instruction.
   1879   DCHECK_EQ(R12, hidden_reg);
   1880   __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
   1881 
   1882   if (receiver.IsStackSlot()) {
   1883     __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
   1884     // /* HeapReference<Class> */ temp = temp->klass_
   1885     __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
   1886   } else {
   1887     // /* HeapReference<Class> */ temp = receiver->klass_
   1888     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   1889   }
   1890   codegen_->MaybeRecordImplicitNullCheck(invoke);
   1891   // Instead of simply (possibly) unpoisoning `temp` here, we should
   1892   // emit a read barrier for the previous class reference load.
   1893   // However this is not required in practice, as this is an
   1894   // intermediate/temporary reference and because the current
   1895   // concurrent copying collector keeps the from-space memory
   1896   // intact/accessible until the end of the marking phase (the
   1897   // concurrent copying collector may not in the future).
   1898   __ MaybeUnpoisonHeapReference(temp);
   1899   __ LoadFromOffset(kLoadWord, temp, temp,
   1900         mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
   1901   uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
   1902       invoke->GetImtIndex() % ImTable::kSize, kArmPointerSize));
   1903   // temp = temp->GetImtEntryAt(method_offset);
   1904   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
   1905   uint32_t entry_point =
   1906       ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
   1907   // LR = temp->GetEntryPoint();
   1908   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
   1909   // LR();
   1910   __ blx(LR);
   1911   DCHECK(!codegen_->IsLeafMethod());
   1912   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
   1913 }
   1914 
   1915 void LocationsBuilderARM::VisitNeg(HNeg* neg) {
   1916   LocationSummary* locations =
   1917       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   1918   switch (neg->GetResultType()) {
   1919     case Primitive::kPrimInt: {
   1920       locations->SetInAt(0, Location::RequiresRegister());
   1921       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   1922       break;
   1923     }
   1924     case Primitive::kPrimLong: {
   1925       locations->SetInAt(0, Location::RequiresRegister());
   1926       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   1927       break;
   1928     }
   1929 
   1930     case Primitive::kPrimFloat:
   1931     case Primitive::kPrimDouble:
   1932       locations->SetInAt(0, Location::RequiresFpuRegister());
   1933       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   1934       break;
   1935 
   1936     default:
   1937       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
   1938   }
   1939 }
   1940 
   1941 void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
   1942   LocationSummary* locations = neg->GetLocations();
   1943   Location out = locations->Out();
   1944   Location in = locations->InAt(0);
   1945   switch (neg->GetResultType()) {
   1946     case Primitive::kPrimInt:
   1947       DCHECK(in.IsRegister());
   1948       __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
   1949       break;
   1950 
   1951     case Primitive::kPrimLong:
   1952       DCHECK(in.IsRegisterPair());
   1953       // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
   1954       __ rsbs(out.AsRegisterPairLow<Register>(),
   1955               in.AsRegisterPairLow<Register>(),
   1956               ShifterOperand(0));
   1957       // We cannot emit an RSC (Reverse Subtract with Carry)
   1958       // instruction here, as it does not exist in the Thumb-2
   1959       // instruction set.  We use the following approach
   1960       // using SBC and SUB instead.
   1961       //
   1962       // out.hi = -C
   1963       __ sbc(out.AsRegisterPairHigh<Register>(),
   1964              out.AsRegisterPairHigh<Register>(),
   1965              ShifterOperand(out.AsRegisterPairHigh<Register>()));
   1966       // out.hi = out.hi - in.hi
   1967       __ sub(out.AsRegisterPairHigh<Register>(),
   1968              out.AsRegisterPairHigh<Register>(),
   1969              ShifterOperand(in.AsRegisterPairHigh<Register>()));
   1970       break;
   1971 
   1972     case Primitive::kPrimFloat:
   1973       DCHECK(in.IsFpuRegister());
   1974       __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
   1975       break;
   1976 
   1977     case Primitive::kPrimDouble:
   1978       DCHECK(in.IsFpuRegisterPair());
   1979       __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   1980                FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   1981       break;
   1982 
   1983     default:
   1984       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
   1985   }
   1986 }
   1987 
   1988 void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
   1989   Primitive::Type result_type = conversion->GetResultType();
   1990   Primitive::Type input_type = conversion->GetInputType();
   1991   DCHECK_NE(result_type, input_type);
   1992 
   1993   // The float-to-long, double-to-long and long-to-float type conversions
   1994   // rely on a call to the runtime.
   1995   LocationSummary::CallKind call_kind =
   1996       (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
   1997         && result_type == Primitive::kPrimLong)
   1998        || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
   1999       ? LocationSummary::kCall
   2000       : LocationSummary::kNoCall;
   2001   LocationSummary* locations =
   2002       new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
   2003 
   2004   // The Java language does not allow treating boolean as an integral type but
   2005   // our bit representation makes it safe.
   2006 
   2007   switch (result_type) {
   2008     case Primitive::kPrimByte:
   2009       switch (input_type) {
   2010         case Primitive::kPrimLong:
   2011           // Type conversion from long to byte is a result of code transformations.
   2012         case Primitive::kPrimBoolean:
   2013           // Boolean input is a result of code transformations.
   2014         case Primitive::kPrimShort:
   2015         case Primitive::kPrimInt:
   2016         case Primitive::kPrimChar:
   2017           // Processing a Dex `int-to-byte' instruction.
   2018           locations->SetInAt(0, Location::RequiresRegister());
   2019           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2020           break;
   2021 
   2022         default:
   2023           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2024                      << " to " << result_type;
   2025       }
   2026       break;
   2027 
   2028     case Primitive::kPrimShort:
   2029       switch (input_type) {
   2030         case Primitive::kPrimLong:
   2031           // Type conversion from long to short is a result of code transformations.
   2032         case Primitive::kPrimBoolean:
   2033           // Boolean input is a result of code transformations.
   2034         case Primitive::kPrimByte:
   2035         case Primitive::kPrimInt:
   2036         case Primitive::kPrimChar:
   2037           // Processing a Dex `int-to-short' instruction.
   2038           locations->SetInAt(0, Location::RequiresRegister());
   2039           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2040           break;
   2041 
   2042         default:
   2043           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2044                      << " to " << result_type;
   2045       }
   2046       break;
   2047 
   2048     case Primitive::kPrimInt:
   2049       switch (input_type) {
   2050         case Primitive::kPrimLong:
   2051           // Processing a Dex `long-to-int' instruction.
   2052           locations->SetInAt(0, Location::Any());
   2053           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2054           break;
   2055 
   2056         case Primitive::kPrimFloat:
   2057           // Processing a Dex `float-to-int' instruction.
   2058           locations->SetInAt(0, Location::RequiresFpuRegister());
   2059           locations->SetOut(Location::RequiresRegister());
   2060           locations->AddTemp(Location::RequiresFpuRegister());
   2061           break;
   2062 
   2063         case Primitive::kPrimDouble:
   2064           // Processing a Dex `double-to-int' instruction.
   2065           locations->SetInAt(0, Location::RequiresFpuRegister());
   2066           locations->SetOut(Location::RequiresRegister());
   2067           locations->AddTemp(Location::RequiresFpuRegister());
   2068           break;
   2069 
   2070         default:
   2071           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2072                      << " to " << result_type;
   2073       }
   2074       break;
   2075 
   2076     case Primitive::kPrimLong:
   2077       switch (input_type) {
   2078         case Primitive::kPrimBoolean:
   2079           // Boolean input is a result of code transformations.
   2080         case Primitive::kPrimByte:
   2081         case Primitive::kPrimShort:
   2082         case Primitive::kPrimInt:
   2083         case Primitive::kPrimChar:
   2084           // Processing a Dex `int-to-long' instruction.
   2085           locations->SetInAt(0, Location::RequiresRegister());
   2086           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2087           break;
   2088 
   2089         case Primitive::kPrimFloat: {
   2090           // Processing a Dex `float-to-long' instruction.
   2091           InvokeRuntimeCallingConvention calling_convention;
   2092           locations->SetInAt(0, Location::FpuRegisterLocation(
   2093               calling_convention.GetFpuRegisterAt(0)));
   2094           locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2095           break;
   2096         }
   2097 
   2098         case Primitive::kPrimDouble: {
   2099           // Processing a Dex `double-to-long' instruction.
   2100           InvokeRuntimeCallingConvention calling_convention;
   2101           locations->SetInAt(0, Location::FpuRegisterPairLocation(
   2102               calling_convention.GetFpuRegisterAt(0),
   2103               calling_convention.GetFpuRegisterAt(1)));
   2104           locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2105           break;
   2106         }
   2107 
   2108         default:
   2109           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2110                      << " to " << result_type;
   2111       }
   2112       break;
   2113 
   2114     case Primitive::kPrimChar:
   2115       switch (input_type) {
   2116         case Primitive::kPrimLong:
   2117           // Type conversion from long to char is a result of code transformations.
   2118         case Primitive::kPrimBoolean:
   2119           // Boolean input is a result of code transformations.
   2120         case Primitive::kPrimByte:
   2121         case Primitive::kPrimShort:
   2122         case Primitive::kPrimInt:
   2123           // Processing a Dex `int-to-char' instruction.
   2124           locations->SetInAt(0, Location::RequiresRegister());
   2125           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2126           break;
   2127 
   2128         default:
   2129           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2130                      << " to " << result_type;
   2131       }
   2132       break;
   2133 
   2134     case Primitive::kPrimFloat:
   2135       switch (input_type) {
   2136         case Primitive::kPrimBoolean:
   2137           // Boolean input is a result of code transformations.
   2138         case Primitive::kPrimByte:
   2139         case Primitive::kPrimShort:
   2140         case Primitive::kPrimInt:
   2141         case Primitive::kPrimChar:
   2142           // Processing a Dex `int-to-float' instruction.
   2143           locations->SetInAt(0, Location::RequiresRegister());
   2144           locations->SetOut(Location::RequiresFpuRegister());
   2145           break;
   2146 
   2147         case Primitive::kPrimLong: {
   2148           // Processing a Dex `long-to-float' instruction.
   2149           InvokeRuntimeCallingConvention calling_convention;
   2150           locations->SetInAt(0, Location::RegisterPairLocation(
   2151               calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2152           locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2153           break;
   2154         }
   2155 
   2156         case Primitive::kPrimDouble:
   2157           // Processing a Dex `double-to-float' instruction.
   2158           locations->SetInAt(0, Location::RequiresFpuRegister());
   2159           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2160           break;
   2161 
   2162         default:
   2163           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2164                      << " to " << result_type;
   2165       };
   2166       break;
   2167 
   2168     case Primitive::kPrimDouble:
   2169       switch (input_type) {
   2170         case Primitive::kPrimBoolean:
   2171           // Boolean input is a result of code transformations.
   2172         case Primitive::kPrimByte:
   2173         case Primitive::kPrimShort:
   2174         case Primitive::kPrimInt:
   2175         case Primitive::kPrimChar:
   2176           // Processing a Dex `int-to-double' instruction.
   2177           locations->SetInAt(0, Location::RequiresRegister());
   2178           locations->SetOut(Location::RequiresFpuRegister());
   2179           break;
   2180 
   2181         case Primitive::kPrimLong:
   2182           // Processing a Dex `long-to-double' instruction.
   2183           locations->SetInAt(0, Location::RequiresRegister());
   2184           locations->SetOut(Location::RequiresFpuRegister());
   2185           locations->AddTemp(Location::RequiresFpuRegister());
   2186           locations->AddTemp(Location::RequiresFpuRegister());
   2187           break;
   2188 
   2189         case Primitive::kPrimFloat:
   2190           // Processing a Dex `float-to-double' instruction.
   2191           locations->SetInAt(0, Location::RequiresFpuRegister());
   2192           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2193           break;
   2194 
   2195         default:
   2196           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2197                      << " to " << result_type;
   2198       };
   2199       break;
   2200 
   2201     default:
   2202       LOG(FATAL) << "Unexpected type conversion from " << input_type
   2203                  << " to " << result_type;
   2204   }
   2205 }
   2206 
   2207 void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
   2208   LocationSummary* locations = conversion->GetLocations();
   2209   Location out = locations->Out();
   2210   Location in = locations->InAt(0);
   2211   Primitive::Type result_type = conversion->GetResultType();
   2212   Primitive::Type input_type = conversion->GetInputType();
   2213   DCHECK_NE(result_type, input_type);
   2214   switch (result_type) {
   2215     case Primitive::kPrimByte:
   2216       switch (input_type) {
   2217         case Primitive::kPrimLong:
   2218           // Type conversion from long to byte is a result of code transformations.
   2219           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
   2220           break;
   2221         case Primitive::kPrimBoolean:
   2222           // Boolean input is a result of code transformations.
   2223         case Primitive::kPrimShort:
   2224         case Primitive::kPrimInt:
   2225         case Primitive::kPrimChar:
   2226           // Processing a Dex `int-to-byte' instruction.
   2227           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
   2228           break;
   2229 
   2230         default:
   2231           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2232                      << " to " << result_type;
   2233       }
   2234       break;
   2235 
   2236     case Primitive::kPrimShort:
   2237       switch (input_type) {
   2238         case Primitive::kPrimLong:
   2239           // Type conversion from long to short is a result of code transformations.
   2240           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
   2241           break;
   2242         case Primitive::kPrimBoolean:
   2243           // Boolean input is a result of code transformations.
   2244         case Primitive::kPrimByte:
   2245         case Primitive::kPrimInt:
   2246         case Primitive::kPrimChar:
   2247           // Processing a Dex `int-to-short' instruction.
   2248           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
   2249           break;
   2250 
   2251         default:
   2252           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2253                      << " to " << result_type;
   2254       }
   2255       break;
   2256 
   2257     case Primitive::kPrimInt:
   2258       switch (input_type) {
   2259         case Primitive::kPrimLong:
   2260           // Processing a Dex `long-to-int' instruction.
   2261           DCHECK(out.IsRegister());
   2262           if (in.IsRegisterPair()) {
   2263             __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
   2264           } else if (in.IsDoubleStackSlot()) {
   2265             __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
   2266           } else {
   2267             DCHECK(in.IsConstant());
   2268             DCHECK(in.GetConstant()->IsLongConstant());
   2269             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
   2270             __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
   2271           }
   2272           break;
   2273 
   2274         case Primitive::kPrimFloat: {
   2275           // Processing a Dex `float-to-int' instruction.
   2276           SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2277           __ vmovs(temp, in.AsFpuRegister<SRegister>());
   2278           __ vcvtis(temp, temp);
   2279           __ vmovrs(out.AsRegister<Register>(), temp);
   2280           break;
   2281         }
   2282 
   2283         case Primitive::kPrimDouble: {
   2284           // Processing a Dex `double-to-int' instruction.
   2285           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2286           DRegister temp_d = FromLowSToD(temp_s);
   2287           __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   2288           __ vcvtid(temp_s, temp_d);
   2289           __ vmovrs(out.AsRegister<Register>(), temp_s);
   2290           break;
   2291         }
   2292 
   2293         default:
   2294           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2295                      << " to " << result_type;
   2296       }
   2297       break;
   2298 
   2299     case Primitive::kPrimLong:
   2300       switch (input_type) {
   2301         case Primitive::kPrimBoolean:
   2302           // Boolean input is a result of code transformations.
   2303         case Primitive::kPrimByte:
   2304         case Primitive::kPrimShort:
   2305         case Primitive::kPrimInt:
   2306         case Primitive::kPrimChar:
   2307           // Processing a Dex `int-to-long' instruction.
   2308           DCHECK(out.IsRegisterPair());
   2309           DCHECK(in.IsRegister());
   2310           __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
   2311           // Sign extension.
   2312           __ Asr(out.AsRegisterPairHigh<Register>(),
   2313                  out.AsRegisterPairLow<Register>(),
   2314                  31);
   2315           break;
   2316 
   2317         case Primitive::kPrimFloat:
   2318           // Processing a Dex `float-to-long' instruction.
   2319           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
   2320                                   conversion,
   2321                                   conversion->GetDexPc(),
   2322                                   nullptr);
   2323           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
   2324           break;
   2325 
   2326         case Primitive::kPrimDouble:
   2327           // Processing a Dex `double-to-long' instruction.
   2328           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
   2329                                   conversion,
   2330                                   conversion->GetDexPc(),
   2331                                   nullptr);
   2332           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
   2333           break;
   2334 
   2335         default:
   2336           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2337                      << " to " << result_type;
   2338       }
   2339       break;
   2340 
   2341     case Primitive::kPrimChar:
   2342       switch (input_type) {
   2343         case Primitive::kPrimLong:
   2344           // Type conversion from long to char is a result of code transformations.
   2345           __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
   2346           break;
   2347         case Primitive::kPrimBoolean:
   2348           // Boolean input is a result of code transformations.
   2349         case Primitive::kPrimByte:
   2350         case Primitive::kPrimShort:
   2351         case Primitive::kPrimInt:
   2352           // Processing a Dex `int-to-char' instruction.
   2353           __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
   2354           break;
   2355 
   2356         default:
   2357           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2358                      << " to " << result_type;
   2359       }
   2360       break;
   2361 
   2362     case Primitive::kPrimFloat:
   2363       switch (input_type) {
   2364         case Primitive::kPrimBoolean:
   2365           // Boolean input is a result of code transformations.
   2366         case Primitive::kPrimByte:
   2367         case Primitive::kPrimShort:
   2368         case Primitive::kPrimInt:
   2369         case Primitive::kPrimChar: {
   2370           // Processing a Dex `int-to-float' instruction.
   2371           __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
   2372           __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
   2373           break;
   2374         }
   2375 
   2376         case Primitive::kPrimLong:
   2377           // Processing a Dex `long-to-float' instruction.
   2378           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
   2379                                   conversion,
   2380                                   conversion->GetDexPc(),
   2381                                   nullptr);
   2382           CheckEntrypointTypes<kQuickL2f, float, int64_t>();
   2383           break;
   2384 
   2385         case Primitive::kPrimDouble:
   2386           // Processing a Dex `double-to-float' instruction.
   2387           __ vcvtsd(out.AsFpuRegister<SRegister>(),
   2388                     FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   2389           break;
   2390 
   2391         default:
   2392           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2393                      << " to " << result_type;
   2394       };
   2395       break;
   2396 
   2397     case Primitive::kPrimDouble:
   2398       switch (input_type) {
   2399         case Primitive::kPrimBoolean:
   2400           // Boolean input is a result of code transformations.
   2401         case Primitive::kPrimByte:
   2402         case Primitive::kPrimShort:
   2403         case Primitive::kPrimInt:
   2404         case Primitive::kPrimChar: {
   2405           // Processing a Dex `int-to-double' instruction.
   2406           __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
   2407           __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2408                     out.AsFpuRegisterPairLow<SRegister>());
   2409           break;
   2410         }
   2411 
   2412         case Primitive::kPrimLong: {
   2413           // Processing a Dex `long-to-double' instruction.
   2414           Register low = in.AsRegisterPairLow<Register>();
   2415           Register high = in.AsRegisterPairHigh<Register>();
   2416           SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
   2417           DRegister out_d = FromLowSToD(out_s);
   2418           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2419           DRegister temp_d = FromLowSToD(temp_s);
   2420           SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
   2421           DRegister constant_d = FromLowSToD(constant_s);
   2422 
   2423           // temp_d = int-to-double(high)
   2424           __ vmovsr(temp_s, high);
   2425           __ vcvtdi(temp_d, temp_s);
   2426           // constant_d = k2Pow32EncodingForDouble
   2427           __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
   2428           // out_d = unsigned-to-double(low)
   2429           __ vmovsr(out_s, low);
   2430           __ vcvtdu(out_d, out_s);
   2431           // out_d += temp_d * constant_d
   2432           __ vmlad(out_d, temp_d, constant_d);
   2433           break;
   2434         }
   2435 
   2436         case Primitive::kPrimFloat:
   2437           // Processing a Dex `float-to-double' instruction.
   2438           __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2439                     in.AsFpuRegister<SRegister>());
   2440           break;
   2441 
   2442         default:
   2443           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2444                      << " to " << result_type;
   2445       };
   2446       break;
   2447 
   2448     default:
   2449       LOG(FATAL) << "Unexpected type conversion from " << input_type
   2450                  << " to " << result_type;
   2451   }
   2452 }
   2453 
   2454 void LocationsBuilderARM::VisitAdd(HAdd* add) {
   2455   LocationSummary* locations =
   2456       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   2457   switch (add->GetResultType()) {
   2458     case Primitive::kPrimInt: {
   2459       locations->SetInAt(0, Location::RequiresRegister());
   2460       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
   2461       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2462       break;
   2463     }
   2464 
   2465     case Primitive::kPrimLong: {
   2466       locations->SetInAt(0, Location::RequiresRegister());
   2467       locations->SetInAt(1, Location::RequiresRegister());
   2468       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2469       break;
   2470     }
   2471 
   2472     case Primitive::kPrimFloat:
   2473     case Primitive::kPrimDouble: {
   2474       locations->SetInAt(0, Location::RequiresFpuRegister());
   2475       locations->SetInAt(1, Location::RequiresFpuRegister());
   2476       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2477       break;
   2478     }
   2479 
   2480     default:
   2481       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   2482   }
   2483 }
   2484 
   2485 void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
   2486   LocationSummary* locations = add->GetLocations();
   2487   Location out = locations->Out();
   2488   Location first = locations->InAt(0);
   2489   Location second = locations->InAt(1);
   2490   switch (add->GetResultType()) {
   2491     case Primitive::kPrimInt:
   2492       if (second.IsRegister()) {
   2493         __ add(out.AsRegister<Register>(),
   2494                first.AsRegister<Register>(),
   2495                ShifterOperand(second.AsRegister<Register>()));
   2496       } else {
   2497         __ AddConstant(out.AsRegister<Register>(),
   2498                        first.AsRegister<Register>(),
   2499                        second.GetConstant()->AsIntConstant()->GetValue());
   2500       }
   2501       break;
   2502 
   2503     case Primitive::kPrimLong: {
   2504       DCHECK(second.IsRegisterPair());
   2505       __ adds(out.AsRegisterPairLow<Register>(),
   2506               first.AsRegisterPairLow<Register>(),
   2507               ShifterOperand(second.AsRegisterPairLow<Register>()));
   2508       __ adc(out.AsRegisterPairHigh<Register>(),
   2509              first.AsRegisterPairHigh<Register>(),
   2510              ShifterOperand(second.AsRegisterPairHigh<Register>()));
   2511       break;
   2512     }
   2513 
   2514     case Primitive::kPrimFloat:
   2515       __ vadds(out.AsFpuRegister<SRegister>(),
   2516                first.AsFpuRegister<SRegister>(),
   2517                second.AsFpuRegister<SRegister>());
   2518       break;
   2519 
   2520     case Primitive::kPrimDouble:
   2521       __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2522                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2523                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2524       break;
   2525 
   2526     default:
   2527       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   2528   }
   2529 }
   2530 
   2531 void LocationsBuilderARM::VisitSub(HSub* sub) {
   2532   LocationSummary* locations =
   2533       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   2534   switch (sub->GetResultType()) {
   2535     case Primitive::kPrimInt: {
   2536       locations->SetInAt(0, Location::RequiresRegister());
   2537       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
   2538       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2539       break;
   2540     }
   2541 
   2542     case Primitive::kPrimLong: {
   2543       locations->SetInAt(0, Location::RequiresRegister());
   2544       locations->SetInAt(1, Location::RequiresRegister());
   2545       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2546       break;
   2547     }
   2548     case Primitive::kPrimFloat:
   2549     case Primitive::kPrimDouble: {
   2550       locations->SetInAt(0, Location::RequiresFpuRegister());
   2551       locations->SetInAt(1, Location::RequiresFpuRegister());
   2552       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2553       break;
   2554     }
   2555     default:
   2556       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   2557   }
   2558 }
   2559 
   2560 void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
   2561   LocationSummary* locations = sub->GetLocations();
   2562   Location out = locations->Out();
   2563   Location first = locations->InAt(0);
   2564   Location second = locations->InAt(1);
   2565   switch (sub->GetResultType()) {
   2566     case Primitive::kPrimInt: {
   2567       if (second.IsRegister()) {
   2568         __ sub(out.AsRegister<Register>(),
   2569                first.AsRegister<Register>(),
   2570                ShifterOperand(second.AsRegister<Register>()));
   2571       } else {
   2572         __ AddConstant(out.AsRegister<Register>(),
   2573                        first.AsRegister<Register>(),
   2574                        -second.GetConstant()->AsIntConstant()->GetValue());
   2575       }
   2576       break;
   2577     }
   2578 
   2579     case Primitive::kPrimLong: {
   2580       DCHECK(second.IsRegisterPair());
   2581       __ subs(out.AsRegisterPairLow<Register>(),
   2582               first.AsRegisterPairLow<Register>(),
   2583               ShifterOperand(second.AsRegisterPairLow<Register>()));
   2584       __ sbc(out.AsRegisterPairHigh<Register>(),
   2585              first.AsRegisterPairHigh<Register>(),
   2586              ShifterOperand(second.AsRegisterPairHigh<Register>()));
   2587       break;
   2588     }
   2589 
   2590     case Primitive::kPrimFloat: {
   2591       __ vsubs(out.AsFpuRegister<SRegister>(),
   2592                first.AsFpuRegister<SRegister>(),
   2593                second.AsFpuRegister<SRegister>());
   2594       break;
   2595     }
   2596 
   2597     case Primitive::kPrimDouble: {
   2598       __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2599                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2600                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2601       break;
   2602     }
   2603 
   2604 
   2605     default:
   2606       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   2607   }
   2608 }
   2609 
   2610 void LocationsBuilderARM::VisitMul(HMul* mul) {
   2611   LocationSummary* locations =
   2612       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   2613   switch (mul->GetResultType()) {
   2614     case Primitive::kPrimInt:
   2615     case Primitive::kPrimLong:  {
   2616       locations->SetInAt(0, Location::RequiresRegister());
   2617       locations->SetInAt(1, Location::RequiresRegister());
   2618       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2619       break;
   2620     }
   2621 
   2622     case Primitive::kPrimFloat:
   2623     case Primitive::kPrimDouble: {
   2624       locations->SetInAt(0, Location::RequiresFpuRegister());
   2625       locations->SetInAt(1, Location::RequiresFpuRegister());
   2626       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2627       break;
   2628     }
   2629 
   2630     default:
   2631       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   2632   }
   2633 }
   2634 
   2635 void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
   2636   LocationSummary* locations = mul->GetLocations();
   2637   Location out = locations->Out();
   2638   Location first = locations->InAt(0);
   2639   Location second = locations->InAt(1);
   2640   switch (mul->GetResultType()) {
   2641     case Primitive::kPrimInt: {
   2642       __ mul(out.AsRegister<Register>(),
   2643              first.AsRegister<Register>(),
   2644              second.AsRegister<Register>());
   2645       break;
   2646     }
   2647     case Primitive::kPrimLong: {
   2648       Register out_hi = out.AsRegisterPairHigh<Register>();
   2649       Register out_lo = out.AsRegisterPairLow<Register>();
   2650       Register in1_hi = first.AsRegisterPairHigh<Register>();
   2651       Register in1_lo = first.AsRegisterPairLow<Register>();
   2652       Register in2_hi = second.AsRegisterPairHigh<Register>();
   2653       Register in2_lo = second.AsRegisterPairLow<Register>();
   2654 
   2655       // Extra checks to protect caused by the existence of R1_R2.
   2656       // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
   2657       // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
   2658       DCHECK_NE(out_hi, in1_lo);
   2659       DCHECK_NE(out_hi, in2_lo);
   2660 
   2661       // input: in1 - 64 bits, in2 - 64 bits
   2662       // output: out
   2663       // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
   2664       // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
   2665       // parts: out.lo = (in1.lo * in2.lo)[31:0]
   2666 
   2667       // IP <- in1.lo * in2.hi
   2668       __ mul(IP, in1_lo, in2_hi);
   2669       // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
   2670       __ mla(out_hi, in1_hi, in2_lo, IP);
   2671       // out.lo <- (in1.lo * in2.lo)[31:0];
   2672       __ umull(out_lo, IP, in1_lo, in2_lo);
   2673       // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
   2674       __ add(out_hi, out_hi, ShifterOperand(IP));
   2675       break;
   2676     }
   2677 
   2678     case Primitive::kPrimFloat: {
   2679       __ vmuls(out.AsFpuRegister<SRegister>(),
   2680                first.AsFpuRegister<SRegister>(),
   2681                second.AsFpuRegister<SRegister>());
   2682       break;
   2683     }
   2684 
   2685     case Primitive::kPrimDouble: {
   2686       __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2687                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2688                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2689       break;
   2690     }
   2691 
   2692     default:
   2693       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   2694   }
   2695 }
   2696 
   2697 void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
   2698   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2699   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2700 
   2701   LocationSummary* locations = instruction->GetLocations();
   2702   Location second = locations->InAt(1);
   2703   DCHECK(second.IsConstant());
   2704 
   2705   Register out = locations->Out().AsRegister<Register>();
   2706   Register dividend = locations->InAt(0).AsRegister<Register>();
   2707   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2708   DCHECK(imm == 1 || imm == -1);
   2709 
   2710   if (instruction->IsRem()) {
   2711     __ LoadImmediate(out, 0);
   2712   } else {
   2713     if (imm == 1) {
   2714       __ Mov(out, dividend);
   2715     } else {
   2716       __ rsb(out, dividend, ShifterOperand(0));
   2717     }
   2718   }
   2719 }
   2720 
   2721 void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
   2722   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2723   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2724 
   2725   LocationSummary* locations = instruction->GetLocations();
   2726   Location second = locations->InAt(1);
   2727   DCHECK(second.IsConstant());
   2728 
   2729   Register out = locations->Out().AsRegister<Register>();
   2730   Register dividend = locations->InAt(0).AsRegister<Register>();
   2731   Register temp = locations->GetTemp(0).AsRegister<Register>();
   2732   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2733   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
   2734   int ctz_imm = CTZ(abs_imm);
   2735 
   2736   if (ctz_imm == 1) {
   2737     __ Lsr(temp, dividend, 32 - ctz_imm);
   2738   } else {
   2739     __ Asr(temp, dividend, 31);
   2740     __ Lsr(temp, temp, 32 - ctz_imm);
   2741   }
   2742   __ add(out, temp, ShifterOperand(dividend));
   2743 
   2744   if (instruction->IsDiv()) {
   2745     __ Asr(out, out, ctz_imm);
   2746     if (imm < 0) {
   2747       __ rsb(out, out, ShifterOperand(0));
   2748     }
   2749   } else {
   2750     __ ubfx(out, out, 0, ctz_imm);
   2751     __ sub(out, out, ShifterOperand(temp));
   2752   }
   2753 }
   2754 
   2755 void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
   2756   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2757   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2758 
   2759   LocationSummary* locations = instruction->GetLocations();
   2760   Location second = locations->InAt(1);
   2761   DCHECK(second.IsConstant());
   2762 
   2763   Register out = locations->Out().AsRegister<Register>();
   2764   Register dividend = locations->InAt(0).AsRegister<Register>();
   2765   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
   2766   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
   2767   int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2768 
   2769   int64_t magic;
   2770   int shift;
   2771   CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
   2772 
   2773   __ LoadImmediate(temp1, magic);
   2774   __ smull(temp2, temp1, dividend, temp1);
   2775 
   2776   if (imm > 0 && magic < 0) {
   2777     __ add(temp1, temp1, ShifterOperand(dividend));
   2778   } else if (imm < 0 && magic > 0) {
   2779     __ sub(temp1, temp1, ShifterOperand(dividend));
   2780   }
   2781 
   2782   if (shift != 0) {
   2783     __ Asr(temp1, temp1, shift);
   2784   }
   2785 
   2786   if (instruction->IsDiv()) {
   2787     __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
   2788   } else {
   2789     __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
   2790     // TODO: Strength reduction for mls.
   2791     __ LoadImmediate(temp2, imm);
   2792     __ mls(out, temp1, temp2, dividend);
   2793   }
   2794 }
   2795 
   2796 void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
   2797   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2798   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2799 
   2800   LocationSummary* locations = instruction->GetLocations();
   2801   Location second = locations->InAt(1);
   2802   DCHECK(second.IsConstant());
   2803 
   2804   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2805   if (imm == 0) {
   2806     // Do not generate anything. DivZeroCheck would prevent any code to be executed.
   2807   } else if (imm == 1 || imm == -1) {
   2808     DivRemOneOrMinusOne(instruction);
   2809   } else if (IsPowerOfTwo(AbsOrMin(imm))) {
   2810     DivRemByPowerOfTwo(instruction);
   2811   } else {
   2812     DCHECK(imm <= -2 || imm >= 2);
   2813     GenerateDivRemWithAnyConstant(instruction);
   2814   }
   2815 }
   2816 
   2817 void LocationsBuilderARM::VisitDiv(HDiv* div) {
   2818   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   2819   if (div->GetResultType() == Primitive::kPrimLong) {
   2820     // pLdiv runtime call.
   2821     call_kind = LocationSummary::kCall;
   2822   } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
   2823     // sdiv will be replaced by other instruction sequence.
   2824   } else if (div->GetResultType() == Primitive::kPrimInt &&
   2825              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2826     // pIdivmod runtime call.
   2827     call_kind = LocationSummary::kCall;
   2828   }
   2829 
   2830   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
   2831 
   2832   switch (div->GetResultType()) {
   2833     case Primitive::kPrimInt: {
   2834       if (div->InputAt(1)->IsConstant()) {
   2835         locations->SetInAt(0, Location::RequiresRegister());
   2836         locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
   2837         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2838         int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
   2839         if (value == 1 || value == 0 || value == -1) {
   2840           // No temp register required.
   2841         } else {
   2842           locations->AddTemp(Location::RequiresRegister());
   2843           if (!IsPowerOfTwo(AbsOrMin(value))) {
   2844             locations->AddTemp(Location::RequiresRegister());
   2845           }
   2846         }
   2847       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2848         locations->SetInAt(0, Location::RequiresRegister());
   2849         locations->SetInAt(1, Location::RequiresRegister());
   2850         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2851       } else {
   2852         InvokeRuntimeCallingConvention calling_convention;
   2853         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2854         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2855         // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
   2856         //       we only need the former.
   2857         locations->SetOut(Location::RegisterLocation(R0));
   2858       }
   2859       break;
   2860     }
   2861     case Primitive::kPrimLong: {
   2862       InvokeRuntimeCallingConvention calling_convention;
   2863       locations->SetInAt(0, Location::RegisterPairLocation(
   2864           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2865       locations->SetInAt(1, Location::RegisterPairLocation(
   2866           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
   2867       locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2868       break;
   2869     }
   2870     case Primitive::kPrimFloat:
   2871     case Primitive::kPrimDouble: {
   2872       locations->SetInAt(0, Location::RequiresFpuRegister());
   2873       locations->SetInAt(1, Location::RequiresFpuRegister());
   2874       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2875       break;
   2876     }
   2877 
   2878     default:
   2879       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
   2880   }
   2881 }
   2882 
   2883 void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
   2884   LocationSummary* locations = div->GetLocations();
   2885   Location out = locations->Out();
   2886   Location first = locations->InAt(0);
   2887   Location second = locations->InAt(1);
   2888 
   2889   switch (div->GetResultType()) {
   2890     case Primitive::kPrimInt: {
   2891       if (second.IsConstant()) {
   2892         GenerateDivRemConstantIntegral(div);
   2893       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2894         __ sdiv(out.AsRegister<Register>(),
   2895                 first.AsRegister<Register>(),
   2896                 second.AsRegister<Register>());
   2897       } else {
   2898         InvokeRuntimeCallingConvention calling_convention;
   2899         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
   2900         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
   2901         DCHECK_EQ(R0, out.AsRegister<Register>());
   2902 
   2903         codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
   2904         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
   2905       }
   2906       break;
   2907     }
   2908 
   2909     case Primitive::kPrimLong: {
   2910       InvokeRuntimeCallingConvention calling_convention;
   2911       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
   2912       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
   2913       DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
   2914       DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
   2915       DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
   2916       DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
   2917 
   2918       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
   2919       CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
   2920       break;
   2921     }
   2922 
   2923     case Primitive::kPrimFloat: {
   2924       __ vdivs(out.AsFpuRegister<SRegister>(),
   2925                first.AsFpuRegister<SRegister>(),
   2926                second.AsFpuRegister<SRegister>());
   2927       break;
   2928     }
   2929 
   2930     case Primitive::kPrimDouble: {
   2931       __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2932                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2933                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2934       break;
   2935     }
   2936 
   2937     default:
   2938       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
   2939   }
   2940 }
   2941 
   2942 void LocationsBuilderARM::VisitRem(HRem* rem) {
   2943   Primitive::Type type = rem->GetResultType();
   2944 
   2945   // Most remainders are implemented in the runtime.
   2946   LocationSummary::CallKind call_kind = LocationSummary::kCall;
   2947   if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
   2948     // sdiv will be replaced by other instruction sequence.
   2949     call_kind = LocationSummary::kNoCall;
   2950   } else if ((rem->GetResultType() == Primitive::kPrimInt)
   2951              && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2952     // Have hardware divide instruction for int, do it with three instructions.
   2953     call_kind = LocationSummary::kNoCall;
   2954   }
   2955 
   2956   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
   2957 
   2958   switch (type) {
   2959     case Primitive::kPrimInt: {
   2960       if (rem->InputAt(1)->IsConstant()) {
   2961         locations->SetInAt(0, Location::RequiresRegister());
   2962         locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
   2963         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2964         int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
   2965         if (value == 1 || value == 0 || value == -1) {
   2966           // No temp register required.
   2967         } else {
   2968           locations->AddTemp(Location::RequiresRegister());
   2969           if (!IsPowerOfTwo(AbsOrMin(value))) {
   2970             locations->AddTemp(Location::RequiresRegister());
   2971           }
   2972         }
   2973       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2974         locations->SetInAt(0, Location::RequiresRegister());
   2975         locations->SetInAt(1, Location::RequiresRegister());
   2976         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2977         locations->AddTemp(Location::RequiresRegister());
   2978       } else {
   2979         InvokeRuntimeCallingConvention calling_convention;
   2980         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2981         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2982         // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
   2983         //       we only need the latter.
   2984         locations->SetOut(Location::RegisterLocation(R1));
   2985       }
   2986       break;
   2987     }
   2988     case Primitive::kPrimLong: {
   2989       InvokeRuntimeCallingConvention calling_convention;
   2990       locations->SetInAt(0, Location::RegisterPairLocation(
   2991           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2992       locations->SetInAt(1, Location::RegisterPairLocation(
   2993           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
   2994       // The runtime helper puts the output in R2,R3.
   2995       locations->SetOut(Location::RegisterPairLocation(R2, R3));
   2996       break;
   2997     }
   2998     case Primitive::kPrimFloat: {
   2999       InvokeRuntimeCallingConvention calling_convention;
   3000       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   3001       locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
   3002       locations->SetOut(Location::FpuRegisterLocation(S0));
   3003       break;
   3004     }
   3005 
   3006     case Primitive::kPrimDouble: {
   3007       InvokeRuntimeCallingConvention calling_convention;
   3008       locations->SetInAt(0, Location::FpuRegisterPairLocation(
   3009           calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
   3010       locations->SetInAt(1, Location::FpuRegisterPairLocation(
   3011           calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
   3012       locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
   3013       break;
   3014     }
   3015 
   3016     default:
   3017       LOG(FATAL) << "Unexpected rem type " << type;
   3018   }
   3019 }
   3020 
   3021 void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
   3022   LocationSummary* locations = rem->GetLocations();
   3023   Location out = locations->Out();
   3024   Location first = locations->InAt(0);
   3025   Location second = locations->InAt(1);
   3026 
   3027   Primitive::Type type = rem->GetResultType();
   3028   switch (type) {
   3029     case Primitive::kPrimInt: {
   3030         if (second.IsConstant()) {
   3031           GenerateDivRemConstantIntegral(rem);
   3032         } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   3033         Register reg1 = first.AsRegister<Register>();
   3034         Register reg2 = second.AsRegister<Register>();
   3035         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3036 
   3037         // temp = reg1 / reg2  (integer division)
   3038         // dest = reg1 - temp * reg2
   3039         __ sdiv(temp, reg1, reg2);
   3040         __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
   3041       } else {
   3042         InvokeRuntimeCallingConvention calling_convention;
   3043         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
   3044         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
   3045         DCHECK_EQ(R1, out.AsRegister<Register>());
   3046 
   3047         codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
   3048         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
   3049       }
   3050       break;
   3051     }
   3052 
   3053     case Primitive::kPrimLong: {
   3054       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
   3055         CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
   3056       break;
   3057     }
   3058 
   3059     case Primitive::kPrimFloat: {
   3060       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
   3061       CheckEntrypointTypes<kQuickFmodf, float, float, float>();
   3062       break;
   3063     }
   3064 
   3065     case Primitive::kPrimDouble: {
   3066       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
   3067       CheckEntrypointTypes<kQuickFmod, double, double, double>();
   3068       break;
   3069     }
   3070 
   3071     default:
   3072       LOG(FATAL) << "Unexpected rem type " << type;
   3073   }
   3074 }
   3075 
   3076 void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
   3077   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   3078       ? LocationSummary::kCallOnSlowPath
   3079       : LocationSummary::kNoCall;
   3080   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   3081   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
   3082   if (instruction->HasUses()) {
   3083     locations->SetOut(Location::SameAsFirstInput());
   3084   }
   3085 }
   3086 
   3087 void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
   3088   SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
   3089   codegen_->AddSlowPath(slow_path);
   3090 
   3091   LocationSummary* locations = instruction->GetLocations();
   3092   Location value = locations->InAt(0);
   3093 
   3094   switch (instruction->GetType()) {
   3095     case Primitive::kPrimBoolean:
   3096     case Primitive::kPrimByte:
   3097     case Primitive::kPrimChar:
   3098     case Primitive::kPrimShort:
   3099     case Primitive::kPrimInt: {
   3100       if (value.IsRegister()) {
   3101         __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
   3102       } else {
   3103         DCHECK(value.IsConstant()) << value;
   3104         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
   3105           __ b(slow_path->GetEntryLabel());
   3106         }
   3107       }
   3108       break;
   3109     }
   3110     case Primitive::kPrimLong: {
   3111       if (value.IsRegisterPair()) {
   3112         __ orrs(IP,
   3113                 value.AsRegisterPairLow<Register>(),
   3114                 ShifterOperand(value.AsRegisterPairHigh<Register>()));
   3115         __ b(slow_path->GetEntryLabel(), EQ);
   3116       } else {
   3117         DCHECK(value.IsConstant()) << value;
   3118         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
   3119           __ b(slow_path->GetEntryLabel());
   3120         }
   3121       }
   3122       break;
   3123     default:
   3124       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
   3125     }
   3126   }
   3127 }
   3128 
   3129 void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
   3130   Register in = locations->InAt(0).AsRegister<Register>();
   3131   Location rhs = locations->InAt(1);
   3132   Register out = locations->Out().AsRegister<Register>();
   3133 
   3134   if (rhs.IsConstant()) {
   3135     // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
   3136     // so map all rotations to a +ve. equivalent in that range.
   3137     // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
   3138     uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
   3139     if (rot) {
   3140       // Rotate, mapping left rotations to right equivalents if necessary.
   3141       // (e.g. left by 2 bits == right by 30.)
   3142       __ Ror(out, in, rot);
   3143     } else if (out != in) {
   3144       __ Mov(out, in);
   3145     }
   3146   } else {
   3147     __ Ror(out, in, rhs.AsRegister<Register>());
   3148   }
   3149 }
   3150 
   3151 // Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
   3152 // rotates by swapping input regs (effectively rotating by the first 32-bits of
   3153 // a larger rotation) or flipping direction (thus treating larger right/left
   3154 // rotations as sub-word sized rotations in the other direction) as appropriate.
   3155 void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
   3156   Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   3157   Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   3158   Location rhs = locations->InAt(1);
   3159   Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
   3160   Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
   3161 
   3162   if (rhs.IsConstant()) {
   3163     uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
   3164     // Map all rotations to +ve. equivalents on the interval [0,63].
   3165     rot &= kMaxLongShiftDistance;
   3166     // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
   3167     // logic below to a simple pair of binary orr.
   3168     // (e.g. 34 bits == in_reg swap + 2 bits right.)
   3169     if (rot >= kArmBitsPerWord) {
   3170       rot -= kArmBitsPerWord;
   3171       std::swap(in_reg_hi, in_reg_lo);
   3172     }
   3173     // Rotate, or mov to out for zero or word size rotations.
   3174     if (rot != 0u) {
   3175       __ Lsr(out_reg_hi, in_reg_hi, rot);
   3176       __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
   3177       __ Lsr(out_reg_lo, in_reg_lo, rot);
   3178       __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
   3179     } else {
   3180       __ Mov(out_reg_lo, in_reg_lo);
   3181       __ Mov(out_reg_hi, in_reg_hi);
   3182     }
   3183   } else {
   3184     Register shift_right = locations->GetTemp(0).AsRegister<Register>();
   3185     Register shift_left = locations->GetTemp(1).AsRegister<Register>();
   3186     Label end;
   3187     Label shift_by_32_plus_shift_right;
   3188 
   3189     __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
   3190     __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
   3191     __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
   3192     __ b(&shift_by_32_plus_shift_right, CC);
   3193 
   3194     // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
   3195     // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
   3196     __ Lsl(out_reg_hi, in_reg_hi, shift_left);
   3197     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
   3198     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
   3199     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
   3200     __ Lsr(shift_left, in_reg_hi, shift_right);
   3201     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
   3202     __ b(&end);
   3203 
   3204     __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
   3205     // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
   3206     // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
   3207     __ Lsr(out_reg_hi, in_reg_hi, shift_right);
   3208     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
   3209     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
   3210     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
   3211     __ Lsl(shift_right, in_reg_hi, shift_left);
   3212     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
   3213 
   3214     __ Bind(&end);
   3215   }
   3216 }
   3217 
   3218 void LocationsBuilderARM::VisitRor(HRor* ror) {
   3219   LocationSummary* locations =
   3220       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
   3221   switch (ror->GetResultType()) {
   3222     case Primitive::kPrimInt: {
   3223       locations->SetInAt(0, Location::RequiresRegister());
   3224       locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
   3225       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3226       break;
   3227     }
   3228     case Primitive::kPrimLong: {
   3229       locations->SetInAt(0, Location::RequiresRegister());
   3230       if (ror->InputAt(1)->IsConstant()) {
   3231         locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
   3232       } else {
   3233         locations->SetInAt(1, Location::RequiresRegister());
   3234         locations->AddTemp(Location::RequiresRegister());
   3235         locations->AddTemp(Location::RequiresRegister());
   3236       }
   3237       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3238       break;
   3239     }
   3240     default:
   3241       LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
   3242   }
   3243 }
   3244 
   3245 void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
   3246   LocationSummary* locations = ror->GetLocations();
   3247   Primitive::Type type = ror->GetResultType();
   3248   switch (type) {
   3249     case Primitive::kPrimInt: {
   3250       HandleIntegerRotate(locations);
   3251       break;
   3252     }
   3253     case Primitive::kPrimLong: {
   3254       HandleLongRotate(locations);
   3255       break;
   3256     }
   3257     default:
   3258       LOG(FATAL) << "Unexpected operation type " << type;
   3259       UNREACHABLE();
   3260   }
   3261 }
   3262 
   3263 void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
   3264   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
   3265 
   3266   LocationSummary* locations =
   3267       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
   3268 
   3269   switch (op->GetResultType()) {
   3270     case Primitive::kPrimInt: {
   3271       locations->SetInAt(0, Location::RequiresRegister());
   3272       if (op->InputAt(1)->IsConstant()) {
   3273         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
   3274         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3275       } else {
   3276         locations->SetInAt(1, Location::RequiresRegister());
   3277         // Make the output overlap, as it will be used to hold the masked
   3278         // second input.
   3279         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3280       }
   3281       break;
   3282     }
   3283     case Primitive::kPrimLong: {
   3284       locations->SetInAt(0, Location::RequiresRegister());
   3285       if (op->InputAt(1)->IsConstant()) {
   3286         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
   3287         // For simplicity, use kOutputOverlap even though we only require that low registers
   3288         // don't clash with high registers which the register allocator currently guarantees.
   3289         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3290       } else {
   3291         locations->SetInAt(1, Location::RequiresRegister());
   3292         locations->AddTemp(Location::RequiresRegister());
   3293         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3294       }
   3295       break;
   3296     }
   3297     default:
   3298       LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
   3299   }
   3300 }
   3301 
   3302 void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
   3303   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
   3304 
   3305   LocationSummary* locations = op->GetLocations();
   3306   Location out = locations->Out();
   3307   Location first = locations->InAt(0);
   3308   Location second = locations->InAt(1);
   3309 
   3310   Primitive::Type type = op->GetResultType();
   3311   switch (type) {
   3312     case Primitive::kPrimInt: {
   3313       Register out_reg = out.AsRegister<Register>();
   3314       Register first_reg = first.AsRegister<Register>();
   3315       if (second.IsRegister()) {
   3316         Register second_reg = second.AsRegister<Register>();
   3317         // ARM doesn't mask the shift count so we need to do it ourselves.
   3318         __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
   3319         if (op->IsShl()) {
   3320           __ Lsl(out_reg, first_reg, out_reg);
   3321         } else if (op->IsShr()) {
   3322           __ Asr(out_reg, first_reg, out_reg);
   3323         } else {
   3324           __ Lsr(out_reg, first_reg, out_reg);
   3325         }
   3326       } else {
   3327         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
   3328         uint32_t shift_value = cst & kMaxIntShiftDistance;
   3329         if (shift_value == 0) {  // ARM does not support shifting with 0 immediate.
   3330           __ Mov(out_reg, first_reg);
   3331         } else if (op->IsShl()) {
   3332           __ Lsl(out_reg, first_reg, shift_value);
   3333         } else if (op->IsShr()) {
   3334           __ Asr(out_reg, first_reg, shift_value);
   3335         } else {
   3336           __ Lsr(out_reg, first_reg, shift_value);
   3337         }
   3338       }
   3339       break;
   3340     }
   3341     case Primitive::kPrimLong: {
   3342       Register o_h = out.AsRegisterPairHigh<Register>();
   3343       Register o_l = out.AsRegisterPairLow<Register>();
   3344 
   3345       Register high = first.AsRegisterPairHigh<Register>();
   3346       Register low = first.AsRegisterPairLow<Register>();
   3347 
   3348       if (second.IsRegister()) {
   3349         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3350 
   3351         Register second_reg = second.AsRegister<Register>();
   3352 
   3353         if (op->IsShl()) {
   3354           __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3355           // Shift the high part
   3356           __ Lsl(o_h, high, o_l);
   3357           // Shift the low part and `or` what overflew on the high part
   3358           __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
   3359           __ Lsr(temp, low, temp);
   3360           __ orr(o_h, o_h, ShifterOperand(temp));
   3361           // If the shift is > 32 bits, override the high part
   3362           __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
   3363           __ it(PL);
   3364           __ Lsl(o_h, low, temp, PL);
   3365           // Shift the low part
   3366           __ Lsl(o_l, low, o_l);
   3367         } else if (op->IsShr()) {
   3368           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3369           // Shift the low part
   3370           __ Lsr(o_l, low, o_h);
   3371           // Shift the high part and `or` what underflew on the low part
   3372           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3373           __ Lsl(temp, high, temp);
   3374           __ orr(o_l, o_l, ShifterOperand(temp));
   3375           // If the shift is > 32 bits, override the low part
   3376           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3377           __ it(PL);
   3378           __ Asr(o_l, high, temp, PL);
   3379           // Shift the high part
   3380           __ Asr(o_h, high, o_h);
   3381         } else {
   3382           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3383           // same as Shr except we use `Lsr`s and not `Asr`s
   3384           __ Lsr(o_l, low, o_h);
   3385           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3386           __ Lsl(temp, high, temp);
   3387           __ orr(o_l, o_l, ShifterOperand(temp));
   3388           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3389           __ it(PL);
   3390           __ Lsr(o_l, high, temp, PL);
   3391           __ Lsr(o_h, high, o_h);
   3392         }
   3393       } else {
   3394         // Register allocator doesn't create partial overlap.
   3395         DCHECK_NE(o_l, high);
   3396         DCHECK_NE(o_h, low);
   3397         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
   3398         uint32_t shift_value = cst & kMaxLongShiftDistance;
   3399         if (shift_value > 32) {
   3400           if (op->IsShl()) {
   3401             __ Lsl(o_h, low, shift_value - 32);
   3402             __ LoadImmediate(o_l, 0);
   3403           } else if (op->IsShr()) {
   3404             __ Asr(o_l, high, shift_value - 32);
   3405             __ Asr(o_h, high, 31);
   3406           } else {
   3407             __ Lsr(o_l, high, shift_value - 32);
   3408             __ LoadImmediate(o_h, 0);
   3409           }
   3410         } else if (shift_value == 32) {
   3411           if (op->IsShl()) {
   3412             __ mov(o_h, ShifterOperand(low));
   3413             __ LoadImmediate(o_l, 0);
   3414           } else if (op->IsShr()) {
   3415             __ mov(o_l, ShifterOperand(high));
   3416             __ Asr(o_h, high, 31);
   3417           } else {
   3418             __ mov(o_l, ShifterOperand(high));
   3419             __ LoadImmediate(o_h, 0);
   3420           }
   3421         } else if (shift_value == 1) {
   3422           if (op->IsShl()) {
   3423             __ Lsls(o_l, low, 1);
   3424             __ adc(o_h, high, ShifterOperand(high));
   3425           } else if (op->IsShr()) {
   3426             __ Asrs(o_h, high, 1);
   3427             __ Rrx(o_l, low);
   3428           } else {
   3429             __ Lsrs(o_h, high, 1);
   3430             __ Rrx(o_l, low);
   3431           }
   3432         } else {
   3433           DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
   3434           if (op->IsShl()) {
   3435             __ Lsl(o_h, high, shift_value);
   3436             __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
   3437             __ Lsl(o_l, low, shift_value);
   3438           } else if (op->IsShr()) {
   3439             __ Lsr(o_l, low, shift_value);
   3440             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
   3441             __ Asr(o_h, high, shift_value);
   3442           } else {
   3443             __ Lsr(o_l, low, shift_value);
   3444             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
   3445             __ Lsr(o_h, high, shift_value);
   3446           }
   3447         }
   3448       }
   3449       break;
   3450     }
   3451     default:
   3452       LOG(FATAL) << "Unexpected operation type " << type;
   3453       UNREACHABLE();
   3454   }
   3455 }
   3456 
   3457 void LocationsBuilderARM::VisitShl(HShl* shl) {
   3458   HandleShift(shl);
   3459 }
   3460 
   3461 void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
   3462   HandleShift(shl);
   3463 }
   3464 
   3465 void LocationsBuilderARM::VisitShr(HShr* shr) {
   3466   HandleShift(shr);
   3467 }
   3468 
   3469 void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
   3470   HandleShift(shr);
   3471 }
   3472 
   3473 void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
   3474   HandleShift(ushr);
   3475 }
   3476 
   3477 void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
   3478   HandleShift(ushr);
   3479 }
   3480 
   3481 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
   3482   LocationSummary* locations =
   3483       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   3484   if (instruction->IsStringAlloc()) {
   3485     locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
   3486   } else {
   3487     InvokeRuntimeCallingConvention calling_convention;
   3488     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   3489     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   3490   }
   3491   locations->SetOut(Location::RegisterLocation(R0));
   3492 }
   3493 
   3494 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
   3495   // Note: if heap poisoning is enabled, the entry point takes cares
   3496   // of poisoning the reference.
   3497   if (instruction->IsStringAlloc()) {
   3498     // String is allocated through StringFactory. Call NewEmptyString entry point.
   3499     Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
   3500     MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
   3501     __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
   3502     __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
   3503     __ blx(LR);
   3504     codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
   3505   } else {
   3506     codegen_->InvokeRuntime(instruction->GetEntrypoint(),
   3507                             instruction,
   3508                             instruction->GetDexPc(),
   3509                             nullptr);
   3510     CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
   3511   }
   3512 }
   3513 
   3514 void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
   3515   LocationSummary* locations =
   3516       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   3517   InvokeRuntimeCallingConvention calling_convention;
   3518   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   3519   locations->SetOut(Location::RegisterLocation(R0));
   3520   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   3521   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   3522 }
   3523 
   3524 void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
   3525   InvokeRuntimeCallingConvention calling_convention;
   3526   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
   3527   // Note: if heap poisoning is enabled, the entry point takes cares
   3528   // of poisoning the reference.
   3529   codegen_->InvokeRuntime(instruction->GetEntrypoint(),
   3530                           instruction,
   3531                           instruction->GetDexPc(),
   3532                           nullptr);
   3533   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
   3534 }
   3535 
   3536 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
   3537   LocationSummary* locations =
   3538       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3539   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
   3540   if (location.IsStackSlot()) {
   3541     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
   3542   } else if (location.IsDoubleStackSlot()) {
   3543     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
   3544   }
   3545   locations->SetOut(location);
   3546 }
   3547 
   3548 void InstructionCodeGeneratorARM::VisitParameterValue(
   3549     HParameterValue* instruction ATTRIBUTE_UNUSED) {
   3550   // Nothing to do, the parameter is already at its location.
   3551 }
   3552 
   3553 void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
   3554   LocationSummary* locations =
   3555       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3556   locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
   3557 }
   3558 
   3559 void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
   3560   // Nothing to do, the method is already at its location.
   3561 }
   3562 
   3563 void LocationsBuilderARM::VisitNot(HNot* not_) {
   3564   LocationSummary* locations =
   3565       new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   3566   locations->SetInAt(0, Location::RequiresRegister());
   3567   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3568 }
   3569 
   3570 void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
   3571   LocationSummary* locations = not_->GetLocations();
   3572   Location out = locations->Out();
   3573   Location in = locations->InAt(0);
   3574   switch (not_->GetResultType()) {
   3575     case Primitive::kPrimInt:
   3576       __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
   3577       break;
   3578 
   3579     case Primitive::kPrimLong:
   3580       __ mvn(out.AsRegisterPairLow<Register>(),
   3581              ShifterOperand(in.AsRegisterPairLow<Register>()));
   3582       __ mvn(out.AsRegisterPairHigh<Register>(),
   3583              ShifterOperand(in.AsRegisterPairHigh<Register>()));
   3584       break;
   3585 
   3586     default:
   3587       LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
   3588   }
   3589 }
   3590 
   3591 void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
   3592   LocationSummary* locations =
   3593       new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
   3594   locations->SetInAt(0, Location::RequiresRegister());
   3595   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3596 }
   3597 
   3598 void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
   3599   LocationSummary* locations = bool_not->GetLocations();
   3600   Location out = locations->Out();
   3601   Location in = locations->InAt(0);
   3602   __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
   3603 }
   3604 
   3605 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
   3606   LocationSummary* locations =
   3607       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   3608   switch (compare->InputAt(0)->GetType()) {
   3609     case Primitive::kPrimBoolean:
   3610     case Primitive::kPrimByte:
   3611     case Primitive::kPrimShort:
   3612     case Primitive::kPrimChar:
   3613     case Primitive::kPrimInt:
   3614     case Primitive::kPrimLong: {
   3615       locations->SetInAt(0, Location::RequiresRegister());
   3616       locations->SetInAt(1, Location::RequiresRegister());
   3617       // Output overlaps because it is written before doing the low comparison.
   3618       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3619       break;
   3620     }
   3621     case Primitive::kPrimFloat:
   3622     case Primitive::kPrimDouble: {
   3623       locations->SetInAt(0, Location::RequiresFpuRegister());
   3624       locations->SetInAt(1, Location::RequiresFpuRegister());
   3625       locations->SetOut(Location::RequiresRegister());
   3626       break;
   3627     }
   3628     default:
   3629       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
   3630   }
   3631 }
   3632 
   3633 void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
   3634   LocationSummary* locations = compare->GetLocations();
   3635   Register out = locations->Out().AsRegister<Register>();
   3636   Location left = locations->InAt(0);
   3637   Location right = locations->InAt(1);
   3638 
   3639   Label less, greater, done;
   3640   Primitive::Type type = compare->InputAt(0)->GetType();
   3641   Condition less_cond;
   3642   switch (type) {
   3643     case Primitive::kPrimBoolean:
   3644     case Primitive::kPrimByte:
   3645     case Primitive::kPrimShort:
   3646     case Primitive::kPrimChar:
   3647     case Primitive::kPrimInt: {
   3648       __ LoadImmediate(out, 0);
   3649       __ cmp(left.AsRegister<Register>(),
   3650              ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
   3651       less_cond = LT;
   3652       break;
   3653     }
   3654     case Primitive::kPrimLong: {
   3655       __ cmp(left.AsRegisterPairHigh<Register>(),
   3656              ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
   3657       __ b(&less, LT);
   3658       __ b(&greater, GT);
   3659       // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
   3660       __ LoadImmediate(out, 0);
   3661       __ cmp(left.AsRegisterPairLow<Register>(),
   3662              ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
   3663       less_cond = LO;
   3664       break;
   3665     }
   3666     case Primitive::kPrimFloat:
   3667     case Primitive::kPrimDouble: {
   3668       __ LoadImmediate(out, 0);
   3669       if (type == Primitive::kPrimFloat) {
   3670         __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
   3671       } else {
   3672         __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
   3673                  FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
   3674       }
   3675       __ vmstat();  // transfer FP status register to ARM APSR.
   3676       less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
   3677       break;
   3678     }
   3679     default:
   3680       LOG(FATAL) << "Unexpected compare type " << type;
   3681       UNREACHABLE();
   3682   }
   3683 
   3684   __ b(&done, EQ);
   3685   __ b(&less, less_cond);
   3686 
   3687   __ Bind(&greater);
   3688   __ LoadImmediate(out, 1);
   3689   __ b(&done);
   3690 
   3691   __ Bind(&less);
   3692   __ LoadImmediate(out, -1);
   3693 
   3694   __ Bind(&done);
   3695 }
   3696 
   3697 void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
   3698   LocationSummary* locations =
   3699       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3700   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
   3701     locations->SetInAt(i, Location::Any());
   3702   }
   3703   locations->SetOut(Location::Any());
   3704 }
   3705 
   3706 void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
   3707   LOG(FATAL) << "Unreachable";
   3708 }
   3709 
   3710 void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
   3711   // TODO (ported from quick): revisit ARM barrier kinds.
   3712   DmbOptions flavor = DmbOptions::ISH;  // Quiet C++ warnings.
   3713   switch (kind) {
   3714     case MemBarrierKind::kAnyStore:
   3715     case MemBarrierKind::kLoadAny:
   3716     case MemBarrierKind::kAnyAny: {
   3717       flavor = DmbOptions::ISH;
   3718       break;
   3719     }
   3720     case MemBarrierKind::kStoreStore: {
   3721       flavor = DmbOptions::ISHST;
   3722       break;
   3723     }
   3724     default:
   3725       LOG(FATAL) << "Unexpected memory barrier " << kind;
   3726   }
   3727   __ dmb(flavor);
   3728 }
   3729 
   3730 void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
   3731                                                          uint32_t offset,
   3732                                                          Register out_lo,
   3733                                                          Register out_hi) {
   3734   if (offset != 0) {
   3735     // Ensure `out_lo` is different from `addr`, so that loading
   3736     // `offset` into `out_lo` does not clutter `addr`.
   3737     DCHECK_NE(out_lo, addr);
   3738     __ LoadImmediate(out_lo, offset);
   3739     __ add(IP, addr, ShifterOperand(out_lo));
   3740     addr = IP;
   3741   }
   3742   __ ldrexd(out_lo, out_hi, addr);
   3743 }
   3744 
   3745 void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
   3746                                                           uint32_t offset,
   3747                                                           Register value_lo,
   3748                                                           Register value_hi,
   3749                                                           Register temp1,
   3750                                                           Register temp2,
   3751                                                           HInstruction* instruction) {
   3752   Label fail;
   3753   if (offset != 0) {
   3754     __ LoadImmediate(temp1, offset);
   3755     __ add(IP, addr, ShifterOperand(temp1));
   3756     addr = IP;
   3757   }
   3758   __ Bind(&fail);
   3759   // We need a load followed by store. (The address used in a STREX instruction must
   3760   // be the same as the address in the most recently executed LDREX instruction.)
   3761   __ ldrexd(temp1, temp2, addr);
   3762   codegen_->MaybeRecordImplicitNullCheck(instruction);
   3763   __ strexd(temp1, value_lo, value_hi, addr);
   3764   __ CompareAndBranchIfNonZero(temp1, &fail);
   3765 }
   3766 
   3767 void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
   3768   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   3769 
   3770   LocationSummary* locations =
   3771       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3772   locations->SetInAt(0, Location::RequiresRegister());
   3773 
   3774   Primitive::Type field_type = field_info.GetFieldType();
   3775   if (Primitive::IsFloatingPointType(field_type)) {
   3776     locations->SetInAt(1, Location::RequiresFpuRegister());
   3777   } else {
   3778     locations->SetInAt(1, Location::RequiresRegister());
   3779   }
   3780 
   3781   bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
   3782   bool generate_volatile = field_info.IsVolatile()
   3783       && is_wide
   3784       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3785   bool needs_write_barrier =
   3786       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   3787   // Temporary registers for the write barrier.
   3788   // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
   3789   if (needs_write_barrier) {
   3790     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
   3791     locations->AddTemp(Location::RequiresRegister());
   3792   } else if (generate_volatile) {
   3793     // ARM encoding have some additional constraints for ldrexd/strexd:
   3794     // - registers need to be consecutive
   3795     // - the first register should be even but not R14.
   3796     // We don't test for ARM yet, and the assertion makes sure that we
   3797     // revisit this if we ever enable ARM encoding.
   3798     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
   3799 
   3800     locations->AddTemp(Location::RequiresRegister());
   3801     locations->AddTemp(Location::RequiresRegister());
   3802     if (field_type == Primitive::kPrimDouble) {
   3803       // For doubles we need two more registers to copy the value.
   3804       locations->AddTemp(Location::RegisterLocation(R2));
   3805       locations->AddTemp(Location::RegisterLocation(R3));
   3806     }
   3807   }
   3808 }
   3809 
   3810 void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
   3811                                                  const FieldInfo& field_info,
   3812                                                  bool value_can_be_null) {
   3813   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   3814 
   3815   LocationSummary* locations = instruction->GetLocations();
   3816   Register base = locations->InAt(0).AsRegister<Register>();
   3817   Location value = locations->InAt(1);
   3818 
   3819   bool is_volatile = field_info.IsVolatile();
   3820   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3821   Primitive::Type field_type = field_info.GetFieldType();
   3822   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   3823   bool needs_write_barrier =
   3824       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   3825 
   3826   if (is_volatile) {
   3827     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
   3828   }
   3829 
   3830   switch (field_type) {
   3831     case Primitive::kPrimBoolean:
   3832     case Primitive::kPrimByte: {
   3833       __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
   3834       break;
   3835     }
   3836 
   3837     case Primitive::kPrimShort:
   3838     case Primitive::kPrimChar: {
   3839       __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
   3840       break;
   3841     }
   3842 
   3843     case Primitive::kPrimInt:
   3844     case Primitive::kPrimNot: {
   3845       if (kPoisonHeapReferences && needs_write_barrier) {
   3846         // Note that in the case where `value` is a null reference,
   3847         // we do not enter this block, as a null reference does not
   3848         // need poisoning.
   3849         DCHECK_EQ(field_type, Primitive::kPrimNot);
   3850         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3851         __ Mov(temp, value.AsRegister<Register>());
   3852         __ PoisonHeapReference(temp);
   3853         __ StoreToOffset(kStoreWord, temp, base, offset);
   3854       } else {
   3855         __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
   3856       }
   3857       break;
   3858     }
   3859 
   3860     case Primitive::kPrimLong: {
   3861       if (is_volatile && !atomic_ldrd_strd) {
   3862         GenerateWideAtomicStore(base, offset,
   3863                                 value.AsRegisterPairLow<Register>(),
   3864                                 value.AsRegisterPairHigh<Register>(),
   3865                                 locations->GetTemp(0).AsRegister<Register>(),
   3866                                 locations->GetTemp(1).AsRegister<Register>(),
   3867                                 instruction);
   3868       } else {
   3869         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
   3870         codegen_->MaybeRecordImplicitNullCheck(instruction);
   3871       }
   3872       break;
   3873     }
   3874 
   3875     case Primitive::kPrimFloat: {
   3876       __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
   3877       break;
   3878     }
   3879 
   3880     case Primitive::kPrimDouble: {
   3881       DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
   3882       if (is_volatile && !atomic_ldrd_strd) {
   3883         Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
   3884         Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
   3885 
   3886         __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
   3887 
   3888         GenerateWideAtomicStore(base, offset,
   3889                                 value_reg_lo,
   3890                                 value_reg_hi,
   3891                                 locations->GetTemp(2).AsRegister<Register>(),
   3892                                 locations->GetTemp(3).AsRegister<Register>(),
   3893                                 instruction);
   3894       } else {
   3895         __ StoreDToOffset(value_reg, base, offset);
   3896         codegen_->MaybeRecordImplicitNullCheck(instruction);
   3897       }
   3898       break;
   3899     }
   3900 
   3901     case Primitive::kPrimVoid:
   3902       LOG(FATAL) << "Unreachable type " << field_type;
   3903       UNREACHABLE();
   3904   }
   3905 
   3906   // Longs and doubles are handled in the switch.
   3907   if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
   3908     codegen_->MaybeRecordImplicitNullCheck(instruction);
   3909   }
   3910 
   3911   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
   3912     Register temp = locations->GetTemp(0).AsRegister<Register>();
   3913     Register card = locations->GetTemp(1).AsRegister<Register>();
   3914     codegen_->MarkGCCard(
   3915         temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   3916   }
   3917 
   3918   if (is_volatile) {
   3919     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
   3920   }
   3921 }
   3922 
   3923 void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
   3924   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   3925 
   3926   bool object_field_get_with_read_barrier =
   3927       kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
   3928   LocationSummary* locations =
   3929       new (GetGraph()->GetArena()) LocationSummary(instruction,
   3930                                                    object_field_get_with_read_barrier ?
   3931                                                        LocationSummary::kCallOnSlowPath :
   3932                                                        LocationSummary::kNoCall);
   3933   locations->SetInAt(0, Location::RequiresRegister());
   3934 
   3935   bool volatile_for_double = field_info.IsVolatile()
   3936       && (field_info.GetFieldType() == Primitive::kPrimDouble)
   3937       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3938   // The output overlaps in case of volatile long: we don't want the
   3939   // code generated by GenerateWideAtomicLoad to overwrite the
   3940   // object's location.  Likewise, in the case of an object field get
   3941   // with read barriers enabled, we do not want the load to overwrite
   3942   // the object's location, as we need it to emit the read barrier.
   3943   bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
   3944       object_field_get_with_read_barrier;
   3945 
   3946   if (Primitive::IsFloatingPointType(instruction->GetType())) {
   3947     locations->SetOut(Location::RequiresFpuRegister());
   3948   } else {
   3949     locations->SetOut(Location::RequiresRegister(),
   3950                       (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
   3951   }
   3952   if (volatile_for_double) {
   3953     // ARM encoding have some additional constraints for ldrexd/strexd:
   3954     // - registers need to be consecutive
   3955     // - the first register should be even but not R14.
   3956     // We don't test for ARM yet, and the assertion makes sure that we
   3957     // revisit this if we ever enable ARM encoding.
   3958     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
   3959     locations->AddTemp(Location::RequiresRegister());
   3960     locations->AddTemp(Location::RequiresRegister());
   3961   } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
   3962     // We need a temporary register for the read barrier marking slow
   3963     // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
   3964     locations->AddTemp(Location::RequiresRegister());
   3965   }
   3966 }
   3967 
   3968 Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
   3969                                                              Opcode opcode) {
   3970   DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
   3971   if (constant->IsConstant() &&
   3972       CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
   3973     return Location::ConstantLocation(constant->AsConstant());
   3974   }
   3975   return Location::RequiresRegister();
   3976 }
   3977 
   3978 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
   3979                                                        Opcode opcode) {
   3980   uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
   3981   if (Primitive::Is64BitType(input_cst->GetType())) {
   3982     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
   3983         CanEncodeConstantAsImmediate(High32Bits(value), opcode);
   3984   } else {
   3985     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
   3986   }
   3987 }
   3988 
   3989 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
   3990   ShifterOperand so;
   3991   ArmAssembler* assembler = codegen_->GetAssembler();
   3992   if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
   3993     return true;
   3994   }
   3995   Opcode neg_opcode = kNoOperand;
   3996   switch (opcode) {
   3997     case AND:
   3998       neg_opcode = BIC;
   3999       break;
   4000     case ORR:
   4001       neg_opcode = ORN;
   4002       break;
   4003     default:
   4004       return false;
   4005   }
   4006   return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
   4007 }
   4008 
   4009 void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
   4010                                                  const FieldInfo& field_info) {
   4011   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   4012 
   4013   LocationSummary* locations = instruction->GetLocations();
   4014   Location base_loc = locations->InAt(0);
   4015   Register base = base_loc.AsRegister<Register>();
   4016   Location out = locations->Out();
   4017   bool is_volatile = field_info.IsVolatile();
   4018   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   4019   Primitive::Type field_type = field_info.GetFieldType();
   4020   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   4021 
   4022   switch (field_type) {
   4023     case Primitive::kPrimBoolean:
   4024       __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
   4025       break;
   4026 
   4027     case Primitive::kPrimByte:
   4028       __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
   4029       break;
   4030 
   4031     case Primitive::kPrimShort:
   4032       __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
   4033       break;
   4034 
   4035     case Primitive::kPrimChar:
   4036       __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
   4037       break;
   4038 
   4039     case Primitive::kPrimInt:
   4040       __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
   4041       break;
   4042 
   4043     case Primitive::kPrimNot: {
   4044       // /* HeapReference<Object> */ out = *(base + offset)
   4045       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   4046         Location temp_loc = locations->GetTemp(0);
   4047         // Note that a potential implicit null check is handled in this
   4048         // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
   4049         codegen_->GenerateFieldLoadWithBakerReadBarrier(
   4050             instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
   4051         if (is_volatile) {
   4052           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4053         }
   4054       } else {
   4055         __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
   4056         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4057         if (is_volatile) {
   4058           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4059         }
   4060         // If read barriers are enabled, emit read barriers other than
   4061         // Baker's using a slow path (and also unpoison the loaded
   4062         // reference, if heap poisoning is enabled).
   4063         codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
   4064       }
   4065       break;
   4066     }
   4067 
   4068     case Primitive::kPrimLong:
   4069       if (is_volatile && !atomic_ldrd_strd) {
   4070         GenerateWideAtomicLoad(base, offset,
   4071                                out.AsRegisterPairLow<Register>(),
   4072                                out.AsRegisterPairHigh<Register>());
   4073       } else {
   4074         __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
   4075       }
   4076       break;
   4077 
   4078     case Primitive::kPrimFloat:
   4079       __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
   4080       break;
   4081 
   4082     case Primitive::kPrimDouble: {
   4083       DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
   4084       if (is_volatile && !atomic_ldrd_strd) {
   4085         Register lo = locations->GetTemp(0).AsRegister<Register>();
   4086         Register hi = locations->GetTemp(1).AsRegister<Register>();
   4087         GenerateWideAtomicLoad(base, offset, lo, hi);
   4088         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4089         __ vmovdrr(out_reg, lo, hi);
   4090       } else {
   4091         __ LoadDFromOffset(out_reg, base, offset);
   4092         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4093       }
   4094       break;
   4095     }
   4096 
   4097     case Primitive::kPrimVoid:
   4098       LOG(FATAL) << "Unreachable type " << field_type;
   4099       UNREACHABLE();
   4100   }
   4101 
   4102   if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
   4103     // Potential implicit null checks, in the case of reference or
   4104     // double fields, are handled in the previous switch statement.
   4105   } else {
   4106     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4107   }
   4108 
   4109   if (is_volatile) {
   4110     if (field_type == Primitive::kPrimNot) {
   4111       // Memory barriers, in the case of references, are also handled
   4112       // in the previous switch statement.
   4113     } else {
   4114       codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4115     }
   4116   }
   4117 }
   4118 
   4119 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   4120   HandleFieldSet(instruction, instruction->GetFieldInfo());
   4121 }
   4122 
   4123 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   4124   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
   4125 }
   4126 
   4127 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   4128   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4129 }
   4130 
   4131 void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   4132   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4133 }
   4134 
   4135 void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
   4136   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4137 }
   4138 
   4139 void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
   4140   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4141 }
   4142 
   4143 void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   4144   HandleFieldSet(instruction, instruction->GetFieldInfo());
   4145 }
   4146 
   4147 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   4148   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
   4149 }
   4150 
   4151 void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
   4152     HUnresolvedInstanceFieldGet* instruction) {
   4153   FieldAccessCallingConventionARM calling_convention;
   4154   codegen_->CreateUnresolvedFieldLocationSummary(
   4155       instruction, instruction->GetFieldType(), calling_convention);
   4156 }
   4157 
   4158 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
   4159     HUnresolvedInstanceFieldGet* instruction) {
   4160   FieldAccessCallingConventionARM calling_convention;
   4161   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4162                                           instruction->GetFieldType(),
   4163                                           instruction->GetFieldIndex(),
   4164                                           instruction->GetDexPc(),
   4165                                           calling_convention);
   4166 }
   4167 
   4168 void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
   4169     HUnresolvedInstanceFieldSet* instruction) {
   4170   FieldAccessCallingConventionARM calling_convention;
   4171   codegen_->CreateUnresolvedFieldLocationSummary(
   4172       instruction, instruction->GetFieldType(), calling_convention);
   4173 }
   4174 
   4175 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
   4176     HUnresolvedInstanceFieldSet* instruction) {
   4177   FieldAccessCallingConventionARM calling_convention;
   4178   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4179                                           instruction->GetFieldType(),
   4180                                           instruction->GetFieldIndex(),
   4181                                           instruction->GetDexPc(),
   4182                                           calling_convention);
   4183 }
   4184 
   4185 void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
   4186     HUnresolvedStaticFieldGet* instruction) {
   4187   FieldAccessCallingConventionARM calling_convention;
   4188   codegen_->CreateUnresolvedFieldLocationSummary(
   4189       instruction, instruction->GetFieldType(), calling_convention);
   4190 }
   4191 
   4192 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
   4193     HUnresolvedStaticFieldGet* instruction) {
   4194   FieldAccessCallingConventionARM calling_convention;
   4195   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4196                                           instruction->GetFieldType(),
   4197                                           instruction->GetFieldIndex(),
   4198                                           instruction->GetDexPc(),
   4199                                           calling_convention);
   4200 }
   4201 
   4202 void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
   4203     HUnresolvedStaticFieldSet* instruction) {
   4204   FieldAccessCallingConventionARM calling_convention;
   4205   codegen_->CreateUnresolvedFieldLocationSummary(
   4206       instruction, instruction->GetFieldType(), calling_convention);
   4207 }
   4208 
   4209 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
   4210     HUnresolvedStaticFieldSet* instruction) {
   4211   FieldAccessCallingConventionARM calling_convention;
   4212   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4213                                           instruction->GetFieldType(),
   4214                                           instruction->GetFieldIndex(),
   4215                                           instruction->GetDexPc(),
   4216                                           calling_convention);
   4217 }
   4218 
   4219 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
   4220   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   4221       ? LocationSummary::kCallOnSlowPath
   4222       : LocationSummary::kNoCall;
   4223   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   4224   locations->SetInAt(0, Location::RequiresRegister());
   4225   if (instruction->HasUses()) {
   4226     locations->SetOut(Location::SameAsFirstInput());
   4227   }
   4228 }
   4229 
   4230 void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
   4231   if (CanMoveNullCheckToUser(instruction)) {
   4232     return;
   4233   }
   4234   Location obj = instruction->GetLocations()->InAt(0);
   4235 
   4236   __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
   4237   RecordPcInfo(instruction, instruction->GetDexPc());
   4238 }
   4239 
   4240 void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
   4241   SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
   4242   AddSlowPath(slow_path);
   4243 
   4244   LocationSummary* locations = instruction->GetLocations();
   4245   Location obj = locations->InAt(0);
   4246 
   4247   __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
   4248 }
   4249 
   4250 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
   4251   codegen_->GenerateNullCheck(instruction);
   4252 }
   4253 
   4254 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
   4255   bool object_array_get_with_read_barrier =
   4256       kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
   4257   LocationSummary* locations =
   4258       new (GetGraph()->GetArena()) LocationSummary(instruction,
   4259                                                    object_array_get_with_read_barrier ?
   4260                                                        LocationSummary::kCallOnSlowPath :
   4261                                                        LocationSummary::kNoCall);
   4262   locations->SetInAt(0, Location::RequiresRegister());
   4263   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   4264   if (Primitive::IsFloatingPointType(instruction->GetType())) {
   4265     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   4266   } else {
   4267     // The output overlaps in the case of an object array get with
   4268     // read barriers enabled: we do not want the move to overwrite the
   4269     // array's location, as we need it to emit the read barrier.
   4270     locations->SetOut(
   4271         Location::RequiresRegister(),
   4272         object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
   4273   }
   4274   // We need a temporary register for the read barrier marking slow
   4275   // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
   4276   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
   4277     locations->AddTemp(Location::RequiresRegister());
   4278   }
   4279 }
   4280 
   4281 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
   4282   LocationSummary* locations = instruction->GetLocations();
   4283   Location obj_loc = locations->InAt(0);
   4284   Register obj = obj_loc.AsRegister<Register>();
   4285   Location index = locations->InAt(1);
   4286   Location out_loc = locations->Out();
   4287 
   4288   Primitive::Type type = instruction->GetType();
   4289   switch (type) {
   4290     case Primitive::kPrimBoolean: {
   4291       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   4292       Register out = out_loc.AsRegister<Register>();
   4293       if (index.IsConstant()) {
   4294         size_t offset =
   4295             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4296         __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
   4297       } else {
   4298         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
   4299         __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
   4300       }
   4301       break;
   4302     }
   4303 
   4304     case Primitive::kPrimByte: {
   4305       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
   4306       Register out = out_loc.AsRegister<Register>();
   4307       if (index.IsConstant()) {
   4308         size_t offset =
   4309             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4310         __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
   4311       } else {
   4312         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
   4313         __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
   4314       }
   4315       break;
   4316     }
   4317 
   4318     case Primitive::kPrimShort: {
   4319       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
   4320       Register out = out_loc.AsRegister<Register>();
   4321       if (index.IsConstant()) {
   4322         size_t offset =
   4323             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4324         __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
   4325       } else {
   4326         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4327         __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
   4328       }
   4329       break;
   4330     }
   4331 
   4332     case Primitive::kPrimChar: {
   4333       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   4334       Register out = out_loc.AsRegister<Register>();
   4335       if (index.IsConstant()) {
   4336         size_t offset =
   4337             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4338         __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
   4339       } else {
   4340         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4341         __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
   4342       }
   4343       break;
   4344     }
   4345 
   4346     case Primitive::kPrimInt: {
   4347       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4348       Register out = out_loc.AsRegister<Register>();
   4349       if (index.IsConstant()) {
   4350         size_t offset =
   4351             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4352         __ LoadFromOffset(kLoadWord, out, obj, offset);
   4353       } else {
   4354         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4355         __ LoadFromOffset(kLoadWord, out, IP, data_offset);
   4356       }
   4357       break;
   4358     }
   4359 
   4360     case Primitive::kPrimNot: {
   4361       static_assert(
   4362           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
   4363           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
   4364       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4365       // /* HeapReference<Object> */ out =
   4366       //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
   4367       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   4368         Location temp = locations->GetTemp(0);
   4369         // Note that a potential implicit null check is handled in this
   4370         // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
   4371         codegen_->GenerateArrayLoadWithBakerReadBarrier(
   4372             instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
   4373       } else {
   4374         Register out = out_loc.AsRegister<Register>();
   4375         if (index.IsConstant()) {
   4376           size_t offset =
   4377               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4378           __ LoadFromOffset(kLoadWord, out, obj, offset);
   4379           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4380           // If read barriers are enabled, emit read barriers other than
   4381           // Baker's using a slow path (and also unpoison the loaded
   4382           // reference, if heap poisoning is enabled).
   4383           codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
   4384         } else {
   4385           __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4386           __ LoadFromOffset(kLoadWord, out, IP, data_offset);
   4387           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4388           // If read barriers are enabled, emit read barriers other than
   4389           // Baker's using a slow path (and also unpoison the loaded
   4390           // reference, if heap poisoning is enabled).
   4391           codegen_->MaybeGenerateReadBarrierSlow(
   4392               instruction, out_loc, out_loc, obj_loc, data_offset, index);
   4393         }
   4394       }
   4395       break;
   4396     }
   4397 
   4398     case Primitive::kPrimLong: {
   4399       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   4400       if (index.IsConstant()) {
   4401         size_t offset =
   4402             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4403         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
   4404       } else {
   4405         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4406         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
   4407       }
   4408       break;
   4409     }
   4410 
   4411     case Primitive::kPrimFloat: {
   4412       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
   4413       SRegister out = out_loc.AsFpuRegister<SRegister>();
   4414       if (index.IsConstant()) {
   4415         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4416         __ LoadSFromOffset(out, obj, offset);
   4417       } else {
   4418         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4419         __ LoadSFromOffset(out, IP, data_offset);
   4420       }
   4421       break;
   4422     }
   4423 
   4424     case Primitive::kPrimDouble: {
   4425       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
   4426       SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
   4427       if (index.IsConstant()) {
   4428         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4429         __ LoadDFromOffset(FromLowSToD(out), obj, offset);
   4430       } else {
   4431         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4432         __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
   4433       }
   4434       break;
   4435     }
   4436 
   4437     case Primitive::kPrimVoid:
   4438       LOG(FATAL) << "Unreachable type " << type;
   4439       UNREACHABLE();
   4440   }
   4441 
   4442   if (type == Primitive::kPrimNot) {
   4443     // Potential implicit null checks, in the case of reference
   4444     // arrays, are handled in the previous switch statement.
   4445   } else {
   4446     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4447   }
   4448 }
   4449 
   4450 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
   4451   Primitive::Type value_type = instruction->GetComponentType();
   4452 
   4453   bool needs_write_barrier =
   4454       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
   4455   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   4456   bool object_array_set_with_read_barrier =
   4457       kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
   4458 
   4459   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
   4460       instruction,
   4461       (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
   4462           LocationSummary::kCallOnSlowPath :
   4463           LocationSummary::kNoCall);
   4464 
   4465   locations->SetInAt(0, Location::RequiresRegister());
   4466   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   4467   if (Primitive::IsFloatingPointType(value_type)) {
   4468     locations->SetInAt(2, Location::RequiresFpuRegister());
   4469   } else {
   4470     locations->SetInAt(2, Location::RequiresRegister());
   4471   }
   4472   if (needs_write_barrier) {
   4473     // Temporary registers for the write barrier.
   4474     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
   4475     locations->AddTemp(Location::RequiresRegister());
   4476   }
   4477 }
   4478 
   4479 void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
   4480   LocationSummary* locations = instruction->GetLocations();
   4481   Location array_loc = locations->InAt(0);
   4482   Register array = array_loc.AsRegister<Register>();
   4483   Location index = locations->InAt(1);
   4484   Primitive::Type value_type = instruction->GetComponentType();
   4485   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   4486   bool needs_write_barrier =
   4487       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
   4488 
   4489   switch (value_type) {
   4490     case Primitive::kPrimBoolean:
   4491     case Primitive::kPrimByte: {
   4492       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   4493       Register value = locations->InAt(2).AsRegister<Register>();
   4494       if (index.IsConstant()) {
   4495         size_t offset =
   4496             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4497         __ StoreToOffset(kStoreByte, value, array, offset);
   4498       } else {
   4499         __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
   4500         __ StoreToOffset(kStoreByte, value, IP, data_offset);
   4501       }
   4502       break;
   4503     }
   4504 
   4505     case Primitive::kPrimShort:
   4506     case Primitive::kPrimChar: {
   4507       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   4508       Register value = locations->InAt(2).AsRegister<Register>();
   4509       if (index.IsConstant()) {
   4510         size_t offset =
   4511             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4512         __ StoreToOffset(kStoreHalfword, value, array, offset);
   4513       } else {
   4514         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4515         __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
   4516       }
   4517       break;
   4518     }
   4519 
   4520     case Primitive::kPrimNot: {
   4521       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4522       Location value_loc = locations->InAt(2);
   4523       Register value = value_loc.AsRegister<Register>();
   4524       Register source = value;
   4525 
   4526       if (instruction->InputAt(2)->IsNullConstant()) {
   4527         // Just setting null.
   4528         if (index.IsConstant()) {
   4529           size_t offset =
   4530               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4531           __ StoreToOffset(kStoreWord, source, array, offset);
   4532         } else {
   4533           DCHECK(index.IsRegister()) << index;
   4534           __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4535           __ StoreToOffset(kStoreWord, source, IP, data_offset);
   4536         }
   4537         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4538         DCHECK(!needs_write_barrier);
   4539         DCHECK(!may_need_runtime_call_for_type_check);
   4540         break;
   4541       }
   4542 
   4543       DCHECK(needs_write_barrier);
   4544       Register temp1 = locations->GetTemp(0).AsRegister<Register>();
   4545       Register temp2 = locations->GetTemp(1).AsRegister<Register>();
   4546       uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   4547       uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   4548       uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   4549       Label done;
   4550       SlowPathCode* slow_path = nullptr;
   4551 
   4552       if (may_need_runtime_call_for_type_check) {
   4553         slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
   4554         codegen_->AddSlowPath(slow_path);
   4555         if (instruction->GetValueCanBeNull()) {
   4556           Label non_zero;
   4557           __ CompareAndBranchIfNonZero(value, &non_zero);
   4558           if (index.IsConstant()) {
   4559             size_t offset =
   4560                (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4561             __ StoreToOffset(kStoreWord, value, array, offset);
   4562           } else {
   4563             DCHECK(index.IsRegister()) << index;
   4564             __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4565             __ StoreToOffset(kStoreWord, value, IP, data_offset);
   4566           }
   4567           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4568           __ b(&done);
   4569           __ Bind(&non_zero);
   4570         }
   4571 
   4572         if (kEmitCompilerReadBarrier) {
   4573           // When read barriers are enabled, the type checking
   4574           // instrumentation requires two read barriers:
   4575           //
   4576           //   __ Mov(temp2, temp1);
   4577           //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
   4578           //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
   4579           //   codegen_->GenerateReadBarrierSlow(
   4580           //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
   4581           //
   4582           //   // /* HeapReference<Class> */ temp2 = value->klass_
   4583           //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
   4584           //   codegen_->GenerateReadBarrierSlow(
   4585           //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
   4586           //
   4587           //   __ cmp(temp1, ShifterOperand(temp2));
   4588           //
   4589           // However, the second read barrier may trash `temp`, as it
   4590           // is a temporary register, and as such would not be saved
   4591           // along with live registers before calling the runtime (nor
   4592           // restored afterwards).  So in this case, we bail out and
   4593           // delegate the work to the array set slow path.
   4594           //
   4595           // TODO: Extend the register allocator to support a new
   4596           // "(locally) live temp" location so as to avoid always
   4597           // going into the slow path when read barriers are enabled.
   4598           __ b(slow_path->GetEntryLabel());
   4599         } else {
   4600           // /* HeapReference<Class> */ temp1 = array->klass_
   4601           __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
   4602           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4603           __ MaybeUnpoisonHeapReference(temp1);
   4604 
   4605           // /* HeapReference<Class> */ temp1 = temp1->component_type_
   4606           __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
   4607           // /* HeapReference<Class> */ temp2 = value->klass_
   4608           __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
   4609           // If heap poisoning is enabled, no need to unpoison `temp1`
   4610           // nor `temp2`, as we are comparing two poisoned references.
   4611           __ cmp(temp1, ShifterOperand(temp2));
   4612 
   4613           if (instruction->StaticTypeOfArrayIsObjectArray()) {
   4614             Label do_put;
   4615             __ b(&do_put, EQ);
   4616             // If heap poisoning is enabled, the `temp1` reference has
   4617             // not been unpoisoned yet; unpoison it now.
   4618             __ MaybeUnpoisonHeapReference(temp1);
   4619 
   4620             // /* HeapReference<Class> */ temp1 = temp1->super_class_
   4621             __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
   4622             // If heap poisoning is enabled, no need to unpoison
   4623             // `temp1`, as we are comparing against null below.
   4624             __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
   4625             __ Bind(&do_put);
   4626           } else {
   4627             __ b(slow_path->GetEntryLabel(), NE);
   4628           }
   4629         }
   4630       }
   4631 
   4632       if (kPoisonHeapReferences) {
   4633         // Note that in the case where `value` is a null reference,
   4634         // we do not enter this block, as a null reference does not
   4635         // need poisoning.
   4636         DCHECK_EQ(value_type, Primitive::kPrimNot);
   4637         __ Mov(temp1, value);
   4638         __ PoisonHeapReference(temp1);
   4639         source = temp1;
   4640       }
   4641 
   4642       if (index.IsConstant()) {
   4643         size_t offset =
   4644             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4645         __ StoreToOffset(kStoreWord, source, array, offset);
   4646       } else {
   4647         DCHECK(index.IsRegister()) << index;
   4648         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4649         __ StoreToOffset(kStoreWord, source, IP, data_offset);
   4650       }
   4651 
   4652       if (!may_need_runtime_call_for_type_check) {
   4653         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4654       }
   4655 
   4656       codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
   4657 
   4658       if (done.IsLinked()) {
   4659         __ Bind(&done);
   4660       }
   4661 
   4662       if (slow_path != nullptr) {
   4663         __ Bind(slow_path->GetExitLabel());
   4664       }
   4665 
   4666       break;
   4667     }
   4668 
   4669     case Primitive::kPrimInt: {
   4670       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4671       Register value = locations->InAt(2).AsRegister<Register>();
   4672       if (index.IsConstant()) {
   4673         size_t offset =
   4674             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4675         __ StoreToOffset(kStoreWord, value, array, offset);
   4676       } else {
   4677         DCHECK(index.IsRegister()) << index;
   4678         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4679         __ StoreToOffset(kStoreWord, value, IP, data_offset);
   4680       }
   4681       break;
   4682     }
   4683 
   4684     case Primitive::kPrimLong: {
   4685       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   4686       Location value = locations->InAt(2);
   4687       if (index.IsConstant()) {
   4688         size_t offset =
   4689             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4690         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
   4691       } else {
   4692         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4693         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
   4694       }
   4695       break;
   4696     }
   4697 
   4698     case Primitive::kPrimFloat: {
   4699       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
   4700       Location value = locations->InAt(2);
   4701       DCHECK(value.IsFpuRegister());
   4702       if (index.IsConstant()) {
   4703         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4704         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
   4705       } else {
   4706         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4707         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
   4708       }
   4709       break;
   4710     }
   4711 
   4712     case Primitive::kPrimDouble: {
   4713       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
   4714       Location value = locations->InAt(2);
   4715       DCHECK(value.IsFpuRegisterPair());
   4716       if (index.IsConstant()) {
   4717         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4718         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
   4719       } else {
   4720         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4721         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
   4722       }
   4723 
   4724       break;
   4725     }
   4726 
   4727     case Primitive::kPrimVoid:
   4728       LOG(FATAL) << "Unreachable type " << value_type;
   4729       UNREACHABLE();
   4730   }
   4731 
   4732   // Objects are handled in the switch.
   4733   if (value_type != Primitive::kPrimNot) {
   4734     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4735   }
   4736 }
   4737 
   4738 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
   4739   LocationSummary* locations =
   4740       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   4741   locations->SetInAt(0, Location::RequiresRegister());
   4742   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   4743 }
   4744 
   4745 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
   4746   LocationSummary* locations = instruction->GetLocations();
   4747   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
   4748   Register obj = locations->InAt(0).AsRegister<Register>();
   4749   Register out = locations->Out().AsRegister<Register>();
   4750   __ LoadFromOffset(kLoadWord, out, obj, offset);
   4751   codegen_->MaybeRecordImplicitNullCheck(instruction);
   4752 }
   4753 
   4754 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
   4755   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   4756       ? LocationSummary::kCallOnSlowPath
   4757       : LocationSummary::kNoCall;
   4758   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   4759   locations->SetInAt(0, Location::RequiresRegister());
   4760   locations->SetInAt(1, Location::RequiresRegister());
   4761   if (instruction->HasUses()) {
   4762     locations->SetOut(Location::SameAsFirstInput());
   4763   }
   4764 }
   4765 
   4766 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
   4767   LocationSummary* locations = instruction->GetLocations();
   4768   SlowPathCode* slow_path =
   4769       new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
   4770   codegen_->AddSlowPath(slow_path);
   4771 
   4772   Register index = locations->InAt(0).AsRegister<Register>();
   4773   Register length = locations->InAt(1).AsRegister<Register>();
   4774 
   4775   __ cmp(index, ShifterOperand(length));
   4776   __ b(slow_path->GetEntryLabel(), HS);
   4777 }
   4778 
   4779 void CodeGeneratorARM::MarkGCCard(Register temp,
   4780                                   Register card,
   4781                                   Register object,
   4782                                   Register value,
   4783                                   bool can_be_null) {
   4784   Label is_null;
   4785   if (can_be_null) {
   4786     __ CompareAndBranchIfZero(value, &is_null);
   4787   }
   4788   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
   4789   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   4790   __ strb(card, Address(card, temp));
   4791   if (can_be_null) {
   4792     __ Bind(&is_null);
   4793   }
   4794 }
   4795 
   4796 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
   4797   LOG(FATAL) << "Unreachable";
   4798 }
   4799 
   4800 void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
   4801   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
   4802 }
   4803 
   4804 void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
   4805   new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
   4806 }
   4807 
   4808 void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
   4809   HBasicBlock* block = instruction->GetBlock();
   4810   if (block->GetLoopInformation() != nullptr) {
   4811     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
   4812     // The back edge will generate the suspend check.
   4813     return;
   4814   }
   4815   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
   4816     // The goto will generate the suspend check.
   4817     return;
   4818   }
   4819   GenerateSuspendCheck(instruction, nullptr);
   4820 }
   4821 
   4822 void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
   4823                                                        HBasicBlock* successor) {
   4824   SuspendCheckSlowPathARM* slow_path =
   4825       down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
   4826   if (slow_path == nullptr) {
   4827     slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
   4828     instruction->SetSlowPath(slow_path);
   4829     codegen_->AddSlowPath(slow_path);
   4830     if (successor != nullptr) {
   4831       DCHECK(successor->IsLoopHeader());
   4832       codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
   4833     }
   4834   } else {
   4835     DCHECK_EQ(slow_path->GetSuccessor(), successor);
   4836   }
   4837 
   4838   __ LoadFromOffset(
   4839       kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
   4840   if (successor == nullptr) {
   4841     __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
   4842     __ Bind(slow_path->GetReturnLabel());
   4843   } else {
   4844     __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
   4845     __ b(slow_path->GetEntryLabel());
   4846   }
   4847 }
   4848 
   4849 ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
   4850   return codegen_->GetAssembler();
   4851 }
   4852 
   4853 void ParallelMoveResolverARM::EmitMove(size_t index) {
   4854   MoveOperands* move = moves_[index];
   4855   Location source = move->GetSource();
   4856   Location destination = move->GetDestination();
   4857 
   4858   if (source.IsRegister()) {
   4859     if (destination.IsRegister()) {
   4860       __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
   4861     } else if (destination.IsFpuRegister()) {
   4862       __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
   4863     } else {
   4864       DCHECK(destination.IsStackSlot());
   4865       __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
   4866                        SP, destination.GetStackIndex());
   4867     }
   4868   } else if (source.IsStackSlot()) {
   4869     if (destination.IsRegister()) {
   4870       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
   4871                         SP, source.GetStackIndex());
   4872     } else if (destination.IsFpuRegister()) {
   4873       __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
   4874     } else {
   4875       DCHECK(destination.IsStackSlot());
   4876       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
   4877       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4878     }
   4879   } else if (source.IsFpuRegister()) {
   4880     if (destination.IsRegister()) {
   4881       __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
   4882     } else if (destination.IsFpuRegister()) {
   4883       __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
   4884     } else {
   4885       DCHECK(destination.IsStackSlot());
   4886       __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
   4887     }
   4888   } else if (source.IsDoubleStackSlot()) {
   4889     if (destination.IsDoubleStackSlot()) {
   4890       __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
   4891       __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
   4892     } else if (destination.IsRegisterPair()) {
   4893       DCHECK(ExpectedPairLayout(destination));
   4894       __ LoadFromOffset(
   4895           kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
   4896     } else {
   4897       DCHECK(destination.IsFpuRegisterPair()) << destination;
   4898       __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4899                          SP,
   4900                          source.GetStackIndex());
   4901     }
   4902   } else if (source.IsRegisterPair()) {
   4903     if (destination.IsRegisterPair()) {
   4904       __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
   4905       __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
   4906     } else if (destination.IsFpuRegisterPair()) {
   4907       __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4908                  source.AsRegisterPairLow<Register>(),
   4909                  source.AsRegisterPairHigh<Register>());
   4910     } else {
   4911       DCHECK(destination.IsDoubleStackSlot()) << destination;
   4912       DCHECK(ExpectedPairLayout(source));
   4913       __ StoreToOffset(
   4914           kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
   4915     }
   4916   } else if (source.IsFpuRegisterPair()) {
   4917     if (destination.IsRegisterPair()) {
   4918       __ vmovrrd(destination.AsRegisterPairLow<Register>(),
   4919                  destination.AsRegisterPairHigh<Register>(),
   4920                  FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
   4921     } else if (destination.IsFpuRegisterPair()) {
   4922       __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4923                FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
   4924     } else {
   4925       DCHECK(destination.IsDoubleStackSlot()) << destination;
   4926       __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
   4927                         SP,
   4928                         destination.GetStackIndex());
   4929     }
   4930   } else {
   4931     DCHECK(source.IsConstant()) << source;
   4932     HConstant* constant = source.GetConstant();
   4933     if (constant->IsIntConstant() || constant->IsNullConstant()) {
   4934       int32_t value = CodeGenerator::GetInt32ValueOf(constant);
   4935       if (destination.IsRegister()) {
   4936         __ LoadImmediate(destination.AsRegister<Register>(), value);
   4937       } else {
   4938         DCHECK(destination.IsStackSlot());
   4939         __ LoadImmediate(IP, value);
   4940         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4941       }
   4942     } else if (constant->IsLongConstant()) {
   4943       int64_t value = constant->AsLongConstant()->GetValue();
   4944       if (destination.IsRegisterPair()) {
   4945         __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
   4946         __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
   4947       } else {
   4948         DCHECK(destination.IsDoubleStackSlot()) << destination;
   4949         __ LoadImmediate(IP, Low32Bits(value));
   4950         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4951         __ LoadImmediate(IP, High32Bits(value));
   4952         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
   4953       }
   4954     } else if (constant->IsDoubleConstant()) {
   4955       double value = constant->AsDoubleConstant()->GetValue();
   4956       if (destination.IsFpuRegisterPair()) {
   4957         __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
   4958       } else {
   4959         DCHECK(destination.IsDoubleStackSlot()) << destination;
   4960         uint64_t int_value = bit_cast<uint64_t, double>(value);
   4961         __ LoadImmediate(IP, Low32Bits(int_value));
   4962         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4963         __ LoadImmediate(IP, High32Bits(int_value));
   4964         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
   4965       }
   4966     } else {
   4967       DCHECK(constant->IsFloatConstant()) << constant->DebugName();
   4968       float value = constant->AsFloatConstant()->GetValue();
   4969       if (destination.IsFpuRegister()) {
   4970         __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
   4971       } else {
   4972         DCHECK(destination.IsStackSlot());
   4973         __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
   4974         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4975       }
   4976     }
   4977   }
   4978 }
   4979 
   4980 void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
   4981   __ Mov(IP, reg);
   4982   __ LoadFromOffset(kLoadWord, reg, SP, mem);
   4983   __ StoreToOffset(kStoreWord, IP, SP, mem);
   4984 }
   4985 
   4986 void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
   4987   ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
   4988   int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
   4989   __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
   4990                     SP, mem1 + stack_offset);
   4991   __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
   4992   __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
   4993                    SP, mem2 + stack_offset);
   4994   __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
   4995 }
   4996 
   4997 void ParallelMoveResolverARM::EmitSwap(size_t index) {
   4998   MoveOperands* move = moves_[index];
   4999   Location source = move->GetSource();
   5000   Location destination = move->GetDestination();
   5001 
   5002   if (source.IsRegister() && destination.IsRegister()) {
   5003     DCHECK_NE(source.AsRegister<Register>(), IP);
   5004     DCHECK_NE(destination.AsRegister<Register>(), IP);
   5005     __ Mov(IP, source.AsRegister<Register>());
   5006     __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
   5007     __ Mov(destination.AsRegister<Register>(), IP);
   5008   } else if (source.IsRegister() && destination.IsStackSlot()) {
   5009     Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
   5010   } else if (source.IsStackSlot() && destination.IsRegister()) {
   5011     Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
   5012   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
   5013     Exchange(source.GetStackIndex(), destination.GetStackIndex());
   5014   } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
   5015     __ vmovrs(IP, source.AsFpuRegister<SRegister>());
   5016     __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
   5017     __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
   5018   } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
   5019     __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
   5020     __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
   5021     __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
   5022     __ vmovrrd(destination.AsRegisterPairLow<Register>(),
   5023                destination.AsRegisterPairHigh<Register>(),
   5024                DTMP);
   5025   } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
   5026     Register low_reg = source.IsRegisterPair()
   5027         ? source.AsRegisterPairLow<Register>()
   5028         : destination.AsRegisterPairLow<Register>();
   5029     int mem = source.IsRegisterPair()
   5030         ? destination.GetStackIndex()
   5031         : source.GetStackIndex();
   5032     DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
   5033     __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
   5034     __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
   5035     __ StoreDToOffset(DTMP, SP, mem);
   5036   } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
   5037     DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
   5038     DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
   5039     __ vmovd(DTMP, first);
   5040     __ vmovd(first, second);
   5041     __ vmovd(second, DTMP);
   5042   } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
   5043     DRegister reg = source.IsFpuRegisterPair()
   5044         ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
   5045         : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
   5046     int mem = source.IsFpuRegisterPair()
   5047         ? destination.GetStackIndex()
   5048         : source.GetStackIndex();
   5049     __ vmovd(DTMP, reg);
   5050     __ LoadDFromOffset(reg, SP, mem);
   5051     __ StoreDToOffset(DTMP, SP, mem);
   5052   } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
   5053     SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
   5054                                            : destination.AsFpuRegister<SRegister>();
   5055     int mem = source.IsFpuRegister()
   5056         ? destination.GetStackIndex()
   5057         : source.GetStackIndex();
   5058 
   5059     __ vmovrs(IP, reg);
   5060     __ LoadSFromOffset(reg, SP, mem);
   5061     __ StoreToOffset(kStoreWord, IP, SP, mem);
   5062   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
   5063     Exchange(source.GetStackIndex(), destination.GetStackIndex());
   5064     Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
   5065   } else {
   5066     LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
   5067   }
   5068 }
   5069 
   5070 void ParallelMoveResolverARM::SpillScratch(int reg) {
   5071   __ Push(static_cast<Register>(reg));
   5072 }
   5073 
   5074 void ParallelMoveResolverARM::RestoreScratch(int reg) {
   5075   __ Pop(static_cast<Register>(reg));
   5076 }
   5077 
   5078 void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
   5079   InvokeRuntimeCallingConvention calling_convention;
   5080   CodeGenerator::CreateLoadClassLocationSummary(
   5081       cls,
   5082       Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
   5083       Location::RegisterLocation(R0),
   5084       /* code_generator_supports_read_barrier */ true);
   5085 }
   5086 
   5087 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
   5088   LocationSummary* locations = cls->GetLocations();
   5089   if (cls->NeedsAccessCheck()) {
   5090     codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
   5091     codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
   5092                             cls,
   5093                             cls->GetDexPc(),
   5094                             nullptr);
   5095     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
   5096     return;
   5097   }
   5098 
   5099   Location out_loc = locations->Out();
   5100   Register out = out_loc.AsRegister<Register>();
   5101   Register current_method = locations->InAt(0).AsRegister<Register>();
   5102 
   5103   if (cls->IsReferrersClass()) {
   5104     DCHECK(!cls->CanCallRuntime());
   5105     DCHECK(!cls->MustGenerateClinitCheck());
   5106     // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
   5107     GenerateGcRootFieldLoad(
   5108         cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   5109   } else {
   5110     // /* GcRoot<mirror::Class>[] */ out =
   5111     //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
   5112     __ LoadFromOffset(kLoadWord,
   5113                       out,
   5114                       current_method,
   5115                       ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
   5116     // /* GcRoot<mirror::Class> */ out = out[type_index]
   5117     GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
   5118 
   5119     if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
   5120       DCHECK(cls->CanCallRuntime());
   5121       SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
   5122           cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
   5123       codegen_->AddSlowPath(slow_path);
   5124       if (!cls->IsInDexCache()) {
   5125         __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
   5126       }
   5127       if (cls->MustGenerateClinitCheck()) {
   5128         GenerateClassInitializationCheck(slow_path, out);
   5129       } else {
   5130         __ Bind(slow_path->GetExitLabel());
   5131       }
   5132     }
   5133   }
   5134 }
   5135 
   5136 void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
   5137   LocationSummary* locations =
   5138       new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
   5139   locations->SetInAt(0, Location::RequiresRegister());
   5140   if (check->HasUses()) {
   5141     locations->SetOut(Location::SameAsFirstInput());
   5142   }
   5143 }
   5144 
   5145 void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
   5146   // We assume the class is not null.
   5147   SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
   5148       check->GetLoadClass(), check, check->GetDexPc(), true);
   5149   codegen_->AddSlowPath(slow_path);
   5150   GenerateClassInitializationCheck(slow_path,
   5151                                    check->GetLocations()->InAt(0).AsRegister<Register>());
   5152 }
   5153 
   5154 void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
   5155     SlowPathCode* slow_path, Register class_reg) {
   5156   __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
   5157   __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
   5158   __ b(slow_path->GetEntryLabel(), LT);
   5159   // Even if the initialized flag is set, we may be in a situation where caches are not synced
   5160   // properly. Therefore, we do a memory fence.
   5161   __ dmb(ISH);
   5162   __ Bind(slow_path->GetExitLabel());
   5163 }
   5164 
   5165 HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
   5166     HLoadString::LoadKind desired_string_load_kind) {
   5167   if (kEmitCompilerReadBarrier) {
   5168     switch (desired_string_load_kind) {
   5169       case HLoadString::LoadKind::kBootImageLinkTimeAddress:
   5170       case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
   5171       case HLoadString::LoadKind::kBootImageAddress:
   5172         // TODO: Implement for read barrier.
   5173         return HLoadString::LoadKind::kDexCacheViaMethod;
   5174       default:
   5175         break;
   5176     }
   5177   }
   5178   switch (desired_string_load_kind) {
   5179     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
   5180       DCHECK(!GetCompilerOptions().GetCompilePic());
   5181       break;
   5182     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
   5183       DCHECK(GetCompilerOptions().GetCompilePic());
   5184       break;
   5185     case HLoadString::LoadKind::kBootImageAddress:
   5186       break;
   5187     case HLoadString::LoadKind::kDexCacheAddress:
   5188       DCHECK(Runtime::Current()->UseJitCompilation());
   5189       break;
   5190     case HLoadString::LoadKind::kDexCachePcRelative:
   5191       DCHECK(!Runtime::Current()->UseJitCompilation());
   5192       // We disable pc-relative load when there is an irreducible loop, as the optimization
   5193       // is incompatible with it.
   5194       // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
   5195       // with irreducible loops.
   5196       if (GetGraph()->HasIrreducibleLoops()) {
   5197         return HLoadString::LoadKind::kDexCacheViaMethod;
   5198       }
   5199       break;
   5200     case HLoadString::LoadKind::kDexCacheViaMethod:
   5201       break;
   5202   }
   5203   return desired_string_load_kind;
   5204 }
   5205 
   5206 void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
   5207   LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
   5208       ? LocationSummary::kCallOnSlowPath
   5209       : LocationSummary::kNoCall;
   5210   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
   5211   HLoadString::LoadKind load_kind = load->GetLoadKind();
   5212   if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
   5213       load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
   5214     locations->SetInAt(0, Location::RequiresRegister());
   5215   }
   5216   locations->SetOut(Location::RequiresRegister());
   5217 }
   5218 
   5219 void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
   5220   LocationSummary* locations = load->GetLocations();
   5221   Location out_loc = locations->Out();
   5222   Register out = out_loc.AsRegister<Register>();
   5223 
   5224   switch (load->GetLoadKind()) {
   5225     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
   5226       DCHECK(!kEmitCompilerReadBarrier);
   5227       __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
   5228                                                                       load->GetStringIndex()));
   5229       return;  // No dex cache slow path.
   5230     }
   5231     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
   5232       DCHECK(!kEmitCompilerReadBarrier);
   5233       CodeGeneratorARM::PcRelativePatchInfo* labels =
   5234           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
   5235       __ BindTrackedLabel(&labels->movw_label);
   5236       __ movw(out, /* placeholder */ 0u);
   5237       __ BindTrackedLabel(&labels->movt_label);
   5238       __ movt(out, /* placeholder */ 0u);
   5239       __ BindTrackedLabel(&labels->add_pc_label);
   5240       __ add(out, out, ShifterOperand(PC));
   5241       return;  // No dex cache slow path.
   5242     }
   5243     case HLoadString::LoadKind::kBootImageAddress: {
   5244       DCHECK(!kEmitCompilerReadBarrier);
   5245       DCHECK_NE(load->GetAddress(), 0u);
   5246       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
   5247       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
   5248       return;  // No dex cache slow path.
   5249     }
   5250     case HLoadString::LoadKind::kDexCacheAddress: {
   5251       DCHECK_NE(load->GetAddress(), 0u);
   5252       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
   5253       // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
   5254       // a 128B range. To try and reduce the number of literals if we load multiple strings,
   5255       // simply split the dex cache address to a 128B aligned base loaded from a literal
   5256       // and the remaining offset embedded in the load.
   5257       static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
   5258       DCHECK_ALIGNED(load->GetAddress(), 4u);
   5259       constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
   5260       uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
   5261       uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
   5262       __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
   5263       GenerateGcRootFieldLoad(load, out_loc, out, offset);
   5264       break;
   5265     }
   5266     case HLoadString::LoadKind::kDexCachePcRelative: {
   5267       Register base_reg = locations->InAt(0).AsRegister<Register>();
   5268       HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
   5269       int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
   5270       GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
   5271       break;
   5272     }
   5273     case HLoadString::LoadKind::kDexCacheViaMethod: {
   5274       Register current_method = locations->InAt(0).AsRegister<Register>();
   5275 
   5276       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
   5277       GenerateGcRootFieldLoad(
   5278           load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   5279       // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
   5280       __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
   5281       // /* GcRoot<mirror::String> */ out = out[string_index]
   5282       GenerateGcRootFieldLoad(
   5283           load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
   5284       break;
   5285     }
   5286     default:
   5287       LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
   5288       UNREACHABLE();
   5289   }
   5290 
   5291   if (!load->IsInDexCache()) {
   5292     SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
   5293     codegen_->AddSlowPath(slow_path);
   5294     __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
   5295     __ Bind(slow_path->GetExitLabel());
   5296   }
   5297 }
   5298 
   5299 static int32_t GetExceptionTlsOffset() {
   5300   return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
   5301 }
   5302 
   5303 void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
   5304   LocationSummary* locations =
   5305       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
   5306   locations->SetOut(Location::RequiresRegister());
   5307 }
   5308 
   5309 void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
   5310   Register out = load->GetLocations()->Out().AsRegister<Register>();
   5311   __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
   5312 }
   5313 
   5314 void LocationsBuilderARM::VisitClearException(HClearException* clear) {
   5315   new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
   5316 }
   5317 
   5318 void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
   5319   __ LoadImmediate(IP, 0);
   5320   __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
   5321 }
   5322 
   5323 void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
   5324   LocationSummary* locations =
   5325       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   5326   InvokeRuntimeCallingConvention calling_convention;
   5327   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   5328 }
   5329 
   5330 void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
   5331   codegen_->InvokeRuntime(
   5332       QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
   5333   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
   5334 }
   5335 
   5336 static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
   5337   return kEmitCompilerReadBarrier &&
   5338       (kUseBakerReadBarrier ||
   5339        type_check_kind == TypeCheckKind::kAbstractClassCheck ||
   5340        type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
   5341        type_check_kind == TypeCheckKind::kArrayObjectCheck);
   5342 }
   5343 
   5344 void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
   5345   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   5346   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5347   switch (type_check_kind) {
   5348     case TypeCheckKind::kExactCheck:
   5349     case TypeCheckKind::kAbstractClassCheck:
   5350     case TypeCheckKind::kClassHierarchyCheck:
   5351     case TypeCheckKind::kArrayObjectCheck:
   5352       call_kind =
   5353           kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
   5354       break;
   5355     case TypeCheckKind::kArrayCheck:
   5356     case TypeCheckKind::kUnresolvedCheck:
   5357     case TypeCheckKind::kInterfaceCheck:
   5358       call_kind = LocationSummary::kCallOnSlowPath;
   5359       break;
   5360   }
   5361 
   5362   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   5363   locations->SetInAt(0, Location::RequiresRegister());
   5364   locations->SetInAt(1, Location::RequiresRegister());
   5365   // The "out" register is used as a temporary, so it overlaps with the inputs.
   5366   // Note that TypeCheckSlowPathARM uses this register too.
   5367   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   5368   // When read barriers are enabled, we need a temporary register for
   5369   // some cases.
   5370   if (TypeCheckNeedsATemporary(type_check_kind)) {
   5371     locations->AddTemp(Location::RequiresRegister());
   5372   }
   5373 }
   5374 
   5375 void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
   5376   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5377   LocationSummary* locations = instruction->GetLocations();
   5378   Location obj_loc = locations->InAt(0);
   5379   Register obj = obj_loc.AsRegister<Register>();
   5380   Register cls = locations->InAt(1).AsRegister<Register>();
   5381   Location out_loc = locations->Out();
   5382   Register out = out_loc.AsRegister<Register>();
   5383   Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
   5384       locations->GetTemp(0) :
   5385       Location::NoLocation();
   5386   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   5387   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   5388   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   5389   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
   5390   Label done, zero;
   5391   SlowPathCode* slow_path = nullptr;
   5392 
   5393   // Return 0 if `obj` is null.
   5394   // avoid null check if we know obj is not null.
   5395   if (instruction->MustDoNullCheck()) {
   5396     __ CompareAndBranchIfZero(obj, &zero);
   5397   }
   5398 
   5399   // /* HeapReference<Class> */ out = obj->klass_
   5400   GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
   5401 
   5402   switch (type_check_kind) {
   5403     case TypeCheckKind::kExactCheck: {
   5404       __ cmp(out, ShifterOperand(cls));
   5405       // Classes must be equal for the instanceof to succeed.
   5406       __ b(&zero, NE);
   5407       __ LoadImmediate(out, 1);
   5408       __ b(&done);
   5409       break;
   5410     }
   5411 
   5412     case TypeCheckKind::kAbstractClassCheck: {
   5413       // If the class is abstract, we eagerly fetch the super class of the
   5414       // object to avoid doing a comparison we know will fail.
   5415       Label loop;
   5416       __ Bind(&loop);
   5417       // /* HeapReference<Class> */ out = out->super_class_
   5418       GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
   5419       // If `out` is null, we use it for the result, and jump to `done`.
   5420       __ CompareAndBranchIfZero(out, &done);
   5421       __ cmp(out, ShifterOperand(cls));
   5422       __ b(&loop, NE);
   5423       __ LoadImmediate(out, 1);
   5424       if (zero.IsLinked()) {
   5425         __ b(&done);
   5426       }
   5427       break;
   5428     }
   5429 
   5430     case TypeCheckKind::kClassHierarchyCheck: {
   5431       // Walk over the class hierarchy to find a match.
   5432       Label loop, success;
   5433       __ Bind(&loop);
   5434       __ cmp(out, ShifterOperand(cls));
   5435       __ b(&success, EQ);
   5436       // /* HeapReference<Class> */ out = out->super_class_
   5437       GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
   5438       __ CompareAndBranchIfNonZero(out, &loop);
   5439       // If `out` is null, we use it for the result, and jump to `done`.
   5440       __ b(&done);
   5441       __ Bind(&success);
   5442       __ LoadImmediate(out, 1);
   5443       if (zero.IsLinked()) {
   5444         __ b(&done);
   5445       }
   5446       break;
   5447     }
   5448 
   5449     case TypeCheckKind::kArrayObjectCheck: {
   5450       // Do an exact check.
   5451       Label exact_check;
   5452       __ cmp(out, ShifterOperand(cls));
   5453       __ b(&exact_check, EQ);
   5454       // Otherwise, we need to check that the object's class is a non-primitive array.
   5455       // /* HeapReference<Class> */ out = out->component_type_
   5456       GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
   5457       // If `out` is null, we use it for the result, and jump to `done`.
   5458       __ CompareAndBranchIfZero(out, &done);
   5459       __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
   5460       static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
   5461       __ CompareAndBranchIfNonZero(out, &zero);
   5462       __ Bind(&exact_check);
   5463       __ LoadImmediate(out, 1);
   5464       __ b(&done);
   5465       break;
   5466     }
   5467 
   5468     case TypeCheckKind::kArrayCheck: {
   5469       __ cmp(out, ShifterOperand(cls));
   5470       DCHECK(locations->OnlyCallsOnSlowPath());
   5471       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5472                                                                     /* is_fatal */ false);
   5473       codegen_->AddSlowPath(slow_path);
   5474       __ b(slow_path->GetEntryLabel(), NE);
   5475       __ LoadImmediate(out, 1);
   5476       if (zero.IsLinked()) {
   5477         __ b(&done);
   5478       }
   5479       break;
   5480     }
   5481 
   5482     case TypeCheckKind::kUnresolvedCheck:
   5483     case TypeCheckKind::kInterfaceCheck: {
   5484       // Note that we indeed only call on slow path, but we always go
   5485       // into the slow path for the unresolved and interface check
   5486       // cases.
   5487       //
   5488       // We cannot directly call the InstanceofNonTrivial runtime
   5489       // entry point without resorting to a type checking slow path
   5490       // here (i.e. by calling InvokeRuntime directly), as it would
   5491       // require to assign fixed registers for the inputs of this
   5492       // HInstanceOf instruction (following the runtime calling
   5493       // convention), which might be cluttered by the potential first
   5494       // read barrier emission at the beginning of this method.
   5495       //
   5496       // TODO: Introduce a new runtime entry point taking the object
   5497       // to test (instead of its class) as argument, and let it deal
   5498       // with the read barrier issues. This will let us refactor this
   5499       // case of the `switch` code as it was previously (with a direct
   5500       // call to the runtime not using a type checking slow path).
   5501       // This should also be beneficial for the other cases above.
   5502       DCHECK(locations->OnlyCallsOnSlowPath());
   5503       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5504                                                                     /* is_fatal */ false);
   5505       codegen_->AddSlowPath(slow_path);
   5506       __ b(slow_path->GetEntryLabel());
   5507       if (zero.IsLinked()) {
   5508         __ b(&done);
   5509       }
   5510       break;
   5511     }
   5512   }
   5513 
   5514   if (zero.IsLinked()) {
   5515     __ Bind(&zero);
   5516     __ LoadImmediate(out, 0);
   5517   }
   5518 
   5519   if (done.IsLinked()) {
   5520     __ Bind(&done);
   5521   }
   5522 
   5523   if (slow_path != nullptr) {
   5524     __ Bind(slow_path->GetExitLabel());
   5525   }
   5526 }
   5527 
   5528 void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
   5529   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   5530   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
   5531 
   5532   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5533   switch (type_check_kind) {
   5534     case TypeCheckKind::kExactCheck:
   5535     case TypeCheckKind::kAbstractClassCheck:
   5536     case TypeCheckKind::kClassHierarchyCheck:
   5537     case TypeCheckKind::kArrayObjectCheck:
   5538       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
   5539           LocationSummary::kCallOnSlowPath :
   5540           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
   5541       break;
   5542     case TypeCheckKind::kArrayCheck:
   5543     case TypeCheckKind::kUnresolvedCheck:
   5544     case TypeCheckKind::kInterfaceCheck:
   5545       call_kind = LocationSummary::kCallOnSlowPath;
   5546       break;
   5547   }
   5548 
   5549   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   5550   locations->SetInAt(0, Location::RequiresRegister());
   5551   locations->SetInAt(1, Location::RequiresRegister());
   5552   // Note that TypeCheckSlowPathARM uses this "temp" register too.
   5553   locations->AddTemp(Location::RequiresRegister());
   5554   // When read barriers are enabled, we need an additional temporary
   5555   // register for some cases.
   5556   if (TypeCheckNeedsATemporary(type_check_kind)) {
   5557     locations->AddTemp(Location::RequiresRegister());
   5558   }
   5559 }
   5560 
   5561 void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
   5562   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5563   LocationSummary* locations = instruction->GetLocations();
   5564   Location obj_loc = locations->InAt(0);
   5565   Register obj = obj_loc.AsRegister<Register>();
   5566   Register cls = locations->InAt(1).AsRegister<Register>();
   5567   Location temp_loc = locations->GetTemp(0);
   5568   Register temp = temp_loc.AsRegister<Register>();
   5569   Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
   5570       locations->GetTemp(1) :
   5571       Location::NoLocation();
   5572   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   5573   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   5574   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   5575   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
   5576 
   5577   bool is_type_check_slow_path_fatal =
   5578       (type_check_kind == TypeCheckKind::kExactCheck ||
   5579        type_check_kind == TypeCheckKind::kAbstractClassCheck ||
   5580        type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
   5581        type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
   5582       !instruction->CanThrowIntoCatchBlock();
   5583   SlowPathCode* type_check_slow_path =
   5584       new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5585                                                         is_type_check_slow_path_fatal);
   5586   codegen_->AddSlowPath(type_check_slow_path);
   5587 
   5588   Label done;
   5589   // Avoid null check if we know obj is not null.
   5590   if (instruction->MustDoNullCheck()) {
   5591     __ CompareAndBranchIfZero(obj, &done);
   5592   }
   5593 
   5594   // /* HeapReference<Class> */ temp = obj->klass_
   5595   GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5596 
   5597   switch (type_check_kind) {
   5598     case TypeCheckKind::kExactCheck:
   5599     case TypeCheckKind::kArrayCheck: {
   5600       __ cmp(temp, ShifterOperand(cls));
   5601       // Jump to slow path for throwing the exception or doing a
   5602       // more involved array check.
   5603       __ b(type_check_slow_path->GetEntryLabel(), NE);
   5604       break;
   5605     }
   5606 
   5607     case TypeCheckKind::kAbstractClassCheck: {
   5608       // If the class is abstract, we eagerly fetch the super class of the
   5609       // object to avoid doing a comparison we know will fail.
   5610       Label loop, compare_classes;
   5611       __ Bind(&loop);
   5612       // /* HeapReference<Class> */ temp = temp->super_class_
   5613       GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
   5614 
   5615       // If the class reference currently in `temp` is not null, jump
   5616       // to the `compare_classes` label to compare it with the checked
   5617       // class.
   5618       __ CompareAndBranchIfNonZero(temp, &compare_classes);
   5619       // Otherwise, jump to the slow path to throw the exception.
   5620       //
   5621       // But before, move back the object's class into `temp` before
   5622       // going into the slow path, as it has been overwritten in the
   5623       // meantime.
   5624       // /* HeapReference<Class> */ temp = obj->klass_
   5625       GenerateReferenceLoadTwoRegisters(
   5626           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5627       __ b(type_check_slow_path->GetEntryLabel());
   5628 
   5629       __ Bind(&compare_classes);
   5630       __ cmp(temp, ShifterOperand(cls));
   5631       __ b(&loop, NE);
   5632       break;
   5633     }
   5634 
   5635     case TypeCheckKind::kClassHierarchyCheck: {
   5636       // Walk over the class hierarchy to find a match.
   5637       Label loop;
   5638       __ Bind(&loop);
   5639       __ cmp(temp, ShifterOperand(cls));
   5640       __ b(&done, EQ);
   5641 
   5642       // /* HeapReference<Class> */ temp = temp->super_class_
   5643       GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
   5644 
   5645       // If the class reference currently in `temp` is not null, jump
   5646       // back at the beginning of the loop.
   5647       __ CompareAndBranchIfNonZero(temp, &loop);
   5648       // Otherwise, jump to the slow path to throw the exception.
   5649       //
   5650       // But before, move back the object's class into `temp` before
   5651       // going into the slow path, as it has been overwritten in the
   5652       // meantime.
   5653       // /* HeapReference<Class> */ temp = obj->klass_
   5654       GenerateReferenceLoadTwoRegisters(
   5655           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5656       __ b(type_check_slow_path->GetEntryLabel());
   5657       break;
   5658     }
   5659 
   5660     case TypeCheckKind::kArrayObjectCheck: {
   5661       // Do an exact check.
   5662       Label check_non_primitive_component_type;
   5663       __ cmp(temp, ShifterOperand(cls));
   5664       __ b(&done, EQ);
   5665 
   5666       // Otherwise, we need to check that the object's class is a non-primitive array.
   5667       // /* HeapReference<Class> */ temp = temp->component_type_
   5668       GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
   5669 
   5670       // If the component type is not null (i.e. the object is indeed
   5671       // an array), jump to label `check_non_primitive_component_type`
   5672       // to further check that this component type is not a primitive
   5673       // type.
   5674       __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
   5675       // Otherwise, jump to the slow path to throw the exception.
   5676       //
   5677       // But before, move back the object's class into `temp` before
   5678       // going into the slow path, as it has been overwritten in the
   5679       // meantime.
   5680       // /* HeapReference<Class> */ temp = obj->klass_
   5681       GenerateReferenceLoadTwoRegisters(
   5682           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5683       __ b(type_check_slow_path->GetEntryLabel());
   5684 
   5685       __ Bind(&check_non_primitive_component_type);
   5686       __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
   5687       static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
   5688       __ CompareAndBranchIfZero(temp, &done);
   5689       // Same comment as above regarding `temp` and the slow path.
   5690       // /* HeapReference<Class> */ temp = obj->klass_
   5691       GenerateReferenceLoadTwoRegisters(
   5692           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5693       __ b(type_check_slow_path->GetEntryLabel());
   5694       break;
   5695     }
   5696 
   5697     case TypeCheckKind::kUnresolvedCheck:
   5698     case TypeCheckKind::kInterfaceCheck:
   5699       // We always go into the type check slow path for the unresolved
   5700       // and interface check cases.
   5701       //
   5702       // We cannot directly call the CheckCast runtime entry point
   5703       // without resorting to a type checking slow path here (i.e. by
   5704       // calling InvokeRuntime directly), as it would require to
   5705       // assign fixed registers for the inputs of this HInstanceOf
   5706       // instruction (following the runtime calling convention), which
   5707       // might be cluttered by the potential first read barrier
   5708       // emission at the beginning of this method.
   5709       //
   5710       // TODO: Introduce a new runtime entry point taking the object
   5711       // to test (instead of its class) as argument, and let it deal
   5712       // with the read barrier issues. This will let us refactor this
   5713       // case of the `switch` code as it was previously (with a direct
   5714       // call to the runtime not using a type checking slow path).
   5715       // This should also be beneficial for the other cases above.
   5716       __ b(type_check_slow_path->GetEntryLabel());
   5717       break;
   5718   }
   5719   __ Bind(&done);
   5720 
   5721   __ Bind(type_check_slow_path->GetExitLabel());
   5722 }
   5723 
   5724 void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
   5725   LocationSummary* locations =
   5726       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   5727   InvokeRuntimeCallingConvention calling_convention;
   5728   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   5729 }
   5730 
   5731 void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
   5732   codegen_->InvokeRuntime(instruction->IsEnter()
   5733         ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
   5734       instruction,
   5735       instruction->GetDexPc(),
   5736       nullptr);
   5737   if (instruction->IsEnter()) {
   5738     CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
   5739   } else {
   5740     CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
   5741   }
   5742 }
   5743 
   5744 void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
   5745 void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
   5746 void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
   5747 
   5748 void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
   5749   LocationSummary* locations =
   5750       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   5751   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
   5752          || instruction->GetResultType() == Primitive::kPrimLong);
   5753   // Note: GVN reorders commutative operations to have the constant on the right hand side.
   5754   locations->SetInAt(0, Location::RequiresRegister());
   5755   locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
   5756   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   5757 }
   5758 
   5759 void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
   5760   HandleBitwiseOperation(instruction);
   5761 }
   5762 
   5763 void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
   5764   HandleBitwiseOperation(instruction);
   5765 }
   5766 
   5767 void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
   5768   HandleBitwiseOperation(instruction);
   5769 }
   5770 
   5771 
   5772 void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
   5773   LocationSummary* locations =
   5774       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   5775   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
   5776          || instruction->GetResultType() == Primitive::kPrimLong);
   5777 
   5778   locations->SetInAt(0, Location::RequiresRegister());
   5779   locations->SetInAt(1, Location::RequiresRegister());
   5780   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   5781 }
   5782 
   5783 void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
   5784   LocationSummary* locations = instruction->GetLocations();
   5785   Location first = locations->InAt(0);
   5786   Location second = locations->InAt(1);
   5787   Location out = locations->Out();
   5788 
   5789   if (instruction->GetResultType() == Primitive::kPrimInt) {
   5790     Register first_reg = first.AsRegister<Register>();
   5791     ShifterOperand second_reg(second.AsRegister<Register>());
   5792     Register out_reg = out.AsRegister<Register>();
   5793 
   5794     switch (instruction->GetOpKind()) {
   5795       case HInstruction::kAnd:
   5796         __ bic(out_reg, first_reg, second_reg);
   5797         break;
   5798       case HInstruction::kOr:
   5799         __ orn(out_reg, first_reg, second_reg);
   5800         break;
   5801       // There is no EON on arm.
   5802       case HInstruction::kXor:
   5803       default:
   5804         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
   5805         UNREACHABLE();
   5806     }
   5807     return;
   5808 
   5809   } else {
   5810     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5811     Register first_low = first.AsRegisterPairLow<Register>();
   5812     Register first_high = first.AsRegisterPairHigh<Register>();
   5813     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
   5814     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
   5815     Register out_low = out.AsRegisterPairLow<Register>();
   5816     Register out_high = out.AsRegisterPairHigh<Register>();
   5817 
   5818     switch (instruction->GetOpKind()) {
   5819       case HInstruction::kAnd:
   5820         __ bic(out_low, first_low, second_low);
   5821         __ bic(out_high, first_high, second_high);
   5822         break;
   5823       case HInstruction::kOr:
   5824         __ orn(out_low, first_low, second_low);
   5825         __ orn(out_high, first_high, second_high);
   5826         break;
   5827       // There is no EON on arm.
   5828       case HInstruction::kXor:
   5829       default:
   5830         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
   5831         UNREACHABLE();
   5832     }
   5833   }
   5834 }
   5835 
   5836 void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
   5837   // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
   5838   if (value == 0xffffffffu) {
   5839     if (out != first) {
   5840       __ mov(out, ShifterOperand(first));
   5841     }
   5842     return;
   5843   }
   5844   if (value == 0u) {
   5845     __ mov(out, ShifterOperand(0));
   5846     return;
   5847   }
   5848   ShifterOperand so;
   5849   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
   5850     __ and_(out, first, so);
   5851   } else {
   5852     DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
   5853     __ bic(out, first, ShifterOperand(~value));
   5854   }
   5855 }
   5856 
   5857 void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
   5858   // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
   5859   if (value == 0u) {
   5860     if (out != first) {
   5861       __ mov(out, ShifterOperand(first));
   5862     }
   5863     return;
   5864   }
   5865   if (value == 0xffffffffu) {
   5866     __ mvn(out, ShifterOperand(0));
   5867     return;
   5868   }
   5869   ShifterOperand so;
   5870   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
   5871     __ orr(out, first, so);
   5872   } else {
   5873     DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
   5874     __ orn(out, first, ShifterOperand(~value));
   5875   }
   5876 }
   5877 
   5878 void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
   5879   // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
   5880   if (value == 0u) {
   5881     if (out != first) {
   5882       __ mov(out, ShifterOperand(first));
   5883     }
   5884     return;
   5885   }
   5886   __ eor(out, first, ShifterOperand(value));
   5887 }
   5888 
   5889 void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
   5890   LocationSummary* locations = instruction->GetLocations();
   5891   Location first = locations->InAt(0);
   5892   Location second = locations->InAt(1);
   5893   Location out = locations->Out();
   5894 
   5895   if (second.IsConstant()) {
   5896     uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
   5897     uint32_t value_low = Low32Bits(value);
   5898     if (instruction->GetResultType() == Primitive::kPrimInt) {
   5899       Register first_reg = first.AsRegister<Register>();
   5900       Register out_reg = out.AsRegister<Register>();
   5901       if (instruction->IsAnd()) {
   5902         GenerateAndConst(out_reg, first_reg, value_low);
   5903       } else if (instruction->IsOr()) {
   5904         GenerateOrrConst(out_reg, first_reg, value_low);
   5905       } else {
   5906         DCHECK(instruction->IsXor());
   5907         GenerateEorConst(out_reg, first_reg, value_low);
   5908       }
   5909     } else {
   5910       DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5911       uint32_t value_high = High32Bits(value);
   5912       Register first_low = first.AsRegisterPairLow<Register>();
   5913       Register first_high = first.AsRegisterPairHigh<Register>();
   5914       Register out_low = out.AsRegisterPairLow<Register>();
   5915       Register out_high = out.AsRegisterPairHigh<Register>();
   5916       if (instruction->IsAnd()) {
   5917         GenerateAndConst(out_low, first_low, value_low);
   5918         GenerateAndConst(out_high, first_high, value_high);
   5919       } else if (instruction->IsOr()) {
   5920         GenerateOrrConst(out_low, first_low, value_low);
   5921         GenerateOrrConst(out_high, first_high, value_high);
   5922       } else {
   5923         DCHECK(instruction->IsXor());
   5924         GenerateEorConst(out_low, first_low, value_low);
   5925         GenerateEorConst(out_high, first_high, value_high);
   5926       }
   5927     }
   5928     return;
   5929   }
   5930 
   5931   if (instruction->GetResultType() == Primitive::kPrimInt) {
   5932     Register first_reg = first.AsRegister<Register>();
   5933     ShifterOperand second_reg(second.AsRegister<Register>());
   5934     Register out_reg = out.AsRegister<Register>();
   5935     if (instruction->IsAnd()) {
   5936       __ and_(out_reg, first_reg, second_reg);
   5937     } else if (instruction->IsOr()) {
   5938       __ orr(out_reg, first_reg, second_reg);
   5939     } else {
   5940       DCHECK(instruction->IsXor());
   5941       __ eor(out_reg, first_reg, second_reg);
   5942     }
   5943   } else {
   5944     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5945     Register first_low = first.AsRegisterPairLow<Register>();
   5946     Register first_high = first.AsRegisterPairHigh<Register>();
   5947     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
   5948     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
   5949     Register out_low = out.AsRegisterPairLow<Register>();
   5950     Register out_high = out.AsRegisterPairHigh<Register>();
   5951     if (instruction->IsAnd()) {
   5952       __ and_(out_low, first_low, second_low);
   5953       __ and_(out_high, first_high, second_high);
   5954     } else if (instruction->IsOr()) {
   5955       __ orr(out_low, first_low, second_low);
   5956       __ orr(out_high, first_high, second_high);
   5957     } else {
   5958       DCHECK(instruction->IsXor());
   5959       __ eor(out_low, first_low, second_low);
   5960       __ eor(out_high, first_high, second_high);
   5961     }
   5962   }
   5963 }
   5964 
   5965 void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
   5966                                                                    Location out,
   5967                                                                    uint32_t offset,
   5968                                                                    Location maybe_temp) {
   5969   Register out_reg = out.AsRegister<Register>();
   5970   if (kEmitCompilerReadBarrier) {
   5971     DCHECK(maybe_temp.IsRegister()) << maybe_temp;
   5972     if (kUseBakerReadBarrier) {
   5973       // Load with fast path based Baker's read barrier.
   5974       // /* HeapReference<Object> */ out = *(out + offset)
   5975       codegen_->GenerateFieldLoadWithBakerReadBarrier(
   5976           instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
   5977     } else {
   5978       // Load with slow path based read barrier.
   5979       // Save the value of `out` into `maybe_temp` before overwriting it
   5980       // in the following move operation, as we will need it for the
   5981       // read barrier below.
   5982       __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
   5983       // /* HeapReference<Object> */ out = *(out + offset)
   5984       __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
   5985       codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
   5986     }
   5987   } else {
   5988     // Plain load with no read barrier.
   5989     // /* HeapReference<Object> */ out = *(out + offset)
   5990     __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
   5991     __ MaybeUnpoisonHeapReference(out_reg);
   5992   }
   5993 }
   5994 
   5995 void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
   5996                                                                     Location out,
   5997                                                                     Location obj,
   5998                                                                     uint32_t offset,
   5999                                                                     Location maybe_temp) {
   6000   Register out_reg = out.AsRegister<Register>();
   6001   Register obj_reg = obj.AsRegister<Register>();
   6002   if (kEmitCompilerReadBarrier) {
   6003     if (kUseBakerReadBarrier) {
   6004       DCHECK(maybe_temp.IsRegister()) << maybe_temp;
   6005       // Load with fast path based Baker's read barrier.
   6006       // /* HeapReference<Object> */ out = *(obj + offset)
   6007       codegen_->GenerateFieldLoadWithBakerReadBarrier(
   6008           instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
   6009     } else {
   6010       // Load with slow path based read barrier.
   6011       // /* HeapReference<Object> */ out = *(obj + offset)
   6012       __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
   6013       codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
   6014     }
   6015   } else {
   6016     // Plain load with no read barrier.
   6017     // /* HeapReference<Object> */ out = *(obj + offset)
   6018     __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
   6019     __ MaybeUnpoisonHeapReference(out_reg);
   6020   }
   6021 }
   6022 
   6023 void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
   6024                                                           Location root,
   6025                                                           Register obj,
   6026                                                           uint32_t offset) {
   6027   Register root_reg = root.AsRegister<Register>();
   6028   if (kEmitCompilerReadBarrier) {
   6029     if (kUseBakerReadBarrier) {
   6030       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
   6031       // Baker's read barrier are used:
   6032       //
   6033       //   root = obj.field;
   6034       //   if (Thread::Current()->GetIsGcMarking()) {
   6035       //     root = ReadBarrier::Mark(root)
   6036       //   }
   6037 
   6038       // /* GcRoot<mirror::Object> */ root = *(obj + offset)
   6039       __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
   6040       static_assert(
   6041           sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
   6042           "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
   6043           "have different sizes.");
   6044       static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
   6045                     "art::mirror::CompressedReference<mirror::Object> and int32_t "
   6046                     "have different sizes.");
   6047 
   6048       // Slow path used to mark the GC root `root`.
   6049       SlowPathCode* slow_path =
   6050           new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
   6051       codegen_->AddSlowPath(slow_path);
   6052 
   6053       // IP = Thread::Current()->GetIsGcMarking()
   6054       __ LoadFromOffset(
   6055           kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
   6056       __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
   6057       __ Bind(slow_path->GetExitLabel());
   6058     } else {
   6059       // GC root loaded through a slow path for read barriers other
   6060       // than Baker's.
   6061       // /* GcRoot<mirror::Object>* */ root = obj + offset
   6062       __ AddConstant(root_reg, obj, offset);
   6063       // /* mirror::Object* */ root = root->Read()
   6064       codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
   6065     }
   6066   } else {
   6067     // Plain GC root load with no read barrier.
   6068     // /* GcRoot<mirror::Object> */ root = *(obj + offset)
   6069     __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
   6070     // Note that GC roots are not affected by heap poisoning, thus we
   6071     // do not have to unpoison `root_reg` here.
   6072   }
   6073 }
   6074 
   6075 void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
   6076                                                              Location ref,
   6077                                                              Register obj,
   6078                                                              uint32_t offset,
   6079                                                              Location temp,
   6080                                                              bool needs_null_check) {
   6081   DCHECK(kEmitCompilerReadBarrier);
   6082   DCHECK(kUseBakerReadBarrier);
   6083 
   6084   // /* HeapReference<Object> */ ref = *(obj + offset)
   6085   Location no_index = Location::NoLocation();
   6086   GenerateReferenceLoadWithBakerReadBarrier(
   6087       instruction, ref, obj, offset, no_index, temp, needs_null_check);
   6088 }
   6089 
   6090 void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
   6091                                                              Location ref,
   6092                                                              Register obj,
   6093                                                              uint32_t data_offset,
   6094                                                              Location index,
   6095                                                              Location temp,
   6096                                                              bool needs_null_check) {
   6097   DCHECK(kEmitCompilerReadBarrier);
   6098   DCHECK(kUseBakerReadBarrier);
   6099 
   6100   // /* HeapReference<Object> */ ref =
   6101   //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
   6102   GenerateReferenceLoadWithBakerReadBarrier(
   6103       instruction, ref, obj, data_offset, index, temp, needs_null_check);
   6104 }
   6105 
   6106 void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
   6107                                                                  Location ref,
   6108                                                                  Register obj,
   6109                                                                  uint32_t offset,
   6110                                                                  Location index,
   6111                                                                  Location temp,
   6112                                                                  bool needs_null_check) {
   6113   DCHECK(kEmitCompilerReadBarrier);
   6114   DCHECK(kUseBakerReadBarrier);
   6115 
   6116   // In slow path based read barriers, the read barrier call is
   6117   // inserted after the original load. However, in fast path based
   6118   // Baker's read barriers, we need to perform the load of
   6119   // mirror::Object::monitor_ *before* the original reference load.
   6120   // This load-load ordering is required by the read barrier.
   6121   // The fast path/slow path (for Baker's algorithm) should look like:
   6122   //
   6123   //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
   6124   //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
   6125   //   HeapReference<Object> ref = *src;  // Original reference load.
   6126   //   bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
   6127   //   if (is_gray) {
   6128   //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
   6129   //   }
   6130   //
   6131   // Note: the original implementation in ReadBarrier::Barrier is
   6132   // slightly more complex as it performs additional checks that we do
   6133   // not do here for performance reasons.
   6134 
   6135   Register ref_reg = ref.AsRegister<Register>();
   6136   Register temp_reg = temp.AsRegister<Register>();
   6137   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
   6138 
   6139   // /* int32_t */ monitor = obj->monitor_
   6140   __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
   6141   if (needs_null_check) {
   6142     MaybeRecordImplicitNullCheck(instruction);
   6143   }
   6144   // /* LockWord */ lock_word = LockWord(monitor)
   6145   static_assert(sizeof(LockWord) == sizeof(int32_t),
   6146                 "art::LockWord and int32_t have different sizes.");
   6147   // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
   6148   __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
   6149   __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
   6150   static_assert(
   6151       LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
   6152       "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
   6153 
   6154   // Introduce a dependency on the high bits of rb_state, which shall
   6155   // be all zeroes, to prevent load-load reordering, and without using
   6156   // a memory barrier (which would be more expensive).
   6157   // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
   6158   __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
   6159   // obj is unchanged by this operation, but its value now depends on
   6160   // IP, which depends on temp_reg.
   6161   __ add(obj, obj, ShifterOperand(IP));
   6162 
   6163   // The actual reference load.
   6164   if (index.IsValid()) {
   6165     static_assert(
   6166         sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
   6167         "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
   6168     // /* HeapReference<Object> */ ref =
   6169     //     *(obj + offset + index * sizeof(HeapReference<Object>))
   6170     if (index.IsConstant()) {
   6171       size_t computed_offset =
   6172           (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
   6173       __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
   6174     } else {
   6175       __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   6176       __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
   6177     }
   6178   } else {
   6179     // /* HeapReference<Object> */ ref = *(obj + offset)
   6180     __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
   6181   }
   6182 
   6183   // Object* ref = ref_addr->AsMirrorPtr()
   6184   __ MaybeUnpoisonHeapReference(ref_reg);
   6185 
   6186   // Slow path used to mark the object `ref` when it is gray.
   6187   SlowPathCode* slow_path =
   6188       new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
   6189   AddSlowPath(slow_path);
   6190 
   6191   // if (rb_state == ReadBarrier::gray_ptr_)
   6192   //   ref = ReadBarrier::Mark(ref);
   6193   __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
   6194   __ b(slow_path->GetEntryLabel(), EQ);
   6195   __ Bind(slow_path->GetExitLabel());
   6196 }
   6197 
   6198 void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
   6199                                                Location out,
   6200                                                Location ref,
   6201                                                Location obj,
   6202                                                uint32_t offset,
   6203                                                Location index) {
   6204   DCHECK(kEmitCompilerReadBarrier);
   6205 
   6206   // Insert a slow path based read barrier *after* the reference load.
   6207   //
   6208   // If heap poisoning is enabled, the unpoisoning of the loaded
   6209   // reference will be carried out by the runtime within the slow
   6210   // path.
   6211   //
   6212   // Note that `ref` currently does not get unpoisoned (when heap
   6213   // poisoning is enabled), which is alright as the `ref` argument is
   6214   // not used by the artReadBarrierSlow entry point.
   6215   //
   6216   // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
   6217   SlowPathCode* slow_path = new (GetGraph()->GetArena())
   6218       ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
   6219   AddSlowPath(slow_path);
   6220 
   6221   __ b(slow_path->GetEntryLabel());
   6222   __ Bind(slow_path->GetExitLabel());
   6223 }
   6224 
   6225 void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
   6226                                                     Location out,
   6227                                                     Location ref,
   6228                                                     Location obj,
   6229                                                     uint32_t offset,
   6230                                                     Location index) {
   6231   if (kEmitCompilerReadBarrier) {
   6232     // Baker's read barriers shall be handled by the fast path
   6233     // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
   6234     DCHECK(!kUseBakerReadBarrier);
   6235     // If heap poisoning is enabled, unpoisoning will be taken care of
   6236     // by the runtime within the slow path.
   6237     GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
   6238   } else if (kPoisonHeapReferences) {
   6239     __ UnpoisonHeapReference(out.AsRegister<Register>());
   6240   }
   6241 }
   6242 
   6243 void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
   6244                                                       Location out,
   6245                                                       Location root) {
   6246   DCHECK(kEmitCompilerReadBarrier);
   6247 
   6248   // Insert a slow path based read barrier *after* the GC root load.
   6249   //
   6250   // Note that GC roots are not affected by heap poisoning, so we do
   6251   // not need to do anything special for this here.
   6252   SlowPathCode* slow_path =
   6253       new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
   6254   AddSlowPath(slow_path);
   6255 
   6256   __ b(slow_path->GetEntryLabel());
   6257   __ Bind(slow_path->GetExitLabel());
   6258 }
   6259 
   6260 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
   6261       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
   6262       MethodReference target_method) {
   6263   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
   6264   // We disable pc-relative load when there is an irreducible loop, as the optimization
   6265   // is incompatible with it.
   6266   // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
   6267   // with irreducible loops.
   6268   if (GetGraph()->HasIrreducibleLoops() &&
   6269       (dispatch_info.method_load_kind ==
   6270           HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
   6271     dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
   6272   }
   6273 
   6274   if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
   6275     const DexFile& outer_dex_file = GetGraph()->GetDexFile();
   6276     if (&outer_dex_file != target_method.dex_file) {
   6277       // Calls across dex files are more likely to exceed the available BL range,
   6278       // so use absolute patch with fixup if available and kCallArtMethod otherwise.
   6279       HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
   6280           (desired_dispatch_info.method_load_kind ==
   6281            HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
   6282           ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
   6283           : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
   6284       return HInvokeStaticOrDirect::DispatchInfo {
   6285         dispatch_info.method_load_kind,
   6286         code_ptr_location,
   6287         dispatch_info.method_load_data,
   6288         0u
   6289       };
   6290     }
   6291   }
   6292   return dispatch_info;
   6293 }
   6294 
   6295 Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
   6296                                                                  Register temp) {
   6297   DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
   6298   Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6299   if (!invoke->GetLocations()->Intrinsified()) {
   6300     return location.AsRegister<Register>();
   6301   }
   6302   // For intrinsics we allow any location, so it may be on the stack.
   6303   if (!location.IsRegister()) {
   6304     __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
   6305     return temp;
   6306   }
   6307   // For register locations, check if the register was saved. If so, get it from the stack.
   6308   // Note: There is a chance that the register was saved but not overwritten, so we could
   6309   // save one load. However, since this is just an intrinsic slow path we prefer this
   6310   // simple and more robust approach rather that trying to determine if that's the case.
   6311   SlowPathCode* slow_path = GetCurrentSlowPath();
   6312   DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
   6313   if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
   6314     int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
   6315     __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
   6316     return temp;
   6317   }
   6318   return location.AsRegister<Register>();
   6319 }
   6320 
   6321 void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
   6322   // For better instruction scheduling we load the direct code pointer before the method pointer.
   6323   switch (invoke->GetCodePtrLocation()) {
   6324     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
   6325       // LR = code address from literal pool with link-time patch.
   6326       __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
   6327       break;
   6328     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
   6329       // LR = invoke->GetDirectCodePtr();
   6330       __ LoadImmediate(LR, invoke->GetDirectCodePtr());
   6331       break;
   6332     default:
   6333       break;
   6334   }
   6335 
   6336   Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
   6337   switch (invoke->GetMethodLoadKind()) {
   6338     case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
   6339       // temp = thread->string_init_entrypoint
   6340       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
   6341       break;
   6342     case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
   6343       callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6344       break;
   6345     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
   6346       __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
   6347       break;
   6348     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
   6349       __ LoadLiteral(temp.AsRegister<Register>(),
   6350                      DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
   6351       break;
   6352     case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
   6353       HArmDexCacheArraysBase* base =
   6354           invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
   6355       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
   6356                                                                 temp.AsRegister<Register>());
   6357       int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
   6358       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
   6359       break;
   6360     }
   6361     case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
   6362       Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6363       Register method_reg;
   6364       Register reg = temp.AsRegister<Register>();
   6365       if (current_method.IsRegister()) {
   6366         method_reg = current_method.AsRegister<Register>();
   6367       } else {
   6368         DCHECK(invoke->GetLocations()->Intrinsified());
   6369         DCHECK(!current_method.IsValid());
   6370         method_reg = reg;
   6371         __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
   6372       }
   6373       // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
   6374       __ LoadFromOffset(kLoadWord,
   6375                         reg,
   6376                         method_reg,
   6377                         ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
   6378       // temp = temp[index_in_cache];
   6379       // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
   6380       uint32_t index_in_cache = invoke->GetDexMethodIndex();
   6381       __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
   6382       break;
   6383     }
   6384   }
   6385 
   6386   switch (invoke->GetCodePtrLocation()) {
   6387     case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
   6388       __ bl(GetFrameEntryLabel());
   6389       break;
   6390     case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
   6391       relative_call_patches_.emplace_back(invoke->GetTargetMethod());
   6392       __ BindTrackedLabel(&relative_call_patches_.back().label);
   6393       // Arbitrarily branch to the BL itself, override at link time.
   6394       __ bl(&relative_call_patches_.back().label);
   6395       break;
   6396     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
   6397     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
   6398       // LR prepared above for better instruction scheduling.
   6399       // LR()
   6400       __ blx(LR);
   6401       break;
   6402     case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
   6403       // LR = callee_method->entry_point_from_quick_compiled_code_
   6404       __ LoadFromOffset(
   6405           kLoadWord, LR, callee_method.AsRegister<Register>(),
   6406           ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
   6407       // LR()
   6408       __ blx(LR);
   6409       break;
   6410   }
   6411 
   6412   DCHECK(!IsLeafMethod());
   6413 }
   6414 
   6415 void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
   6416   Register temp = temp_location.AsRegister<Register>();
   6417   uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
   6418       invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
   6419 
   6420   // Use the calling convention instead of the location of the receiver, as
   6421   // intrinsics may have put the receiver in a different register. In the intrinsics
   6422   // slow path, the arguments have been moved to the right place, so here we are
   6423   // guaranteed that the receiver is the first register of the calling convention.
   6424   InvokeDexCallingConvention calling_convention;
   6425   Register receiver = calling_convention.GetRegisterAt(0);
   6426   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   6427   // /* HeapReference<Class> */ temp = receiver->klass_
   6428   __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
   6429   MaybeRecordImplicitNullCheck(invoke);
   6430   // Instead of simply (possibly) unpoisoning `temp` here, we should
   6431   // emit a read barrier for the previous class reference load.
   6432   // However this is not required in practice, as this is an
   6433   // intermediate/temporary reference and because the current
   6434   // concurrent copying collector keeps the from-space memory
   6435   // intact/accessible until the end of the marking phase (the
   6436   // concurrent copying collector may not in the future).
   6437   __ MaybeUnpoisonHeapReference(temp);
   6438   // temp = temp->GetMethodAt(method_offset);
   6439   uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
   6440       kArmWordSize).Int32Value();
   6441   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
   6442   // LR = temp->GetEntryPoint();
   6443   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
   6444   // LR();
   6445   __ blx(LR);
   6446 }
   6447 
   6448 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
   6449     const DexFile& dex_file, uint32_t string_index) {
   6450   return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
   6451 }
   6452 
   6453 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
   6454     const DexFile& dex_file, uint32_t element_offset) {
   6455   return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
   6456 }
   6457 
   6458 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
   6459     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   6460   patches->emplace_back(dex_file, offset_or_index);
   6461   return &patches->back();
   6462 }
   6463 
   6464 Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
   6465                                                              uint32_t string_index) {
   6466   return boot_image_string_patches_.GetOrCreate(
   6467       StringReference(&dex_file, string_index),
   6468       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
   6469 }
   6470 
   6471 Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
   6472   bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
   6473   Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
   6474   return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
   6475 }
   6476 
   6477 Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
   6478   return DeduplicateUint32Literal(address, &uint32_literals_);
   6479 }
   6480 
   6481 void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   6482   DCHECK(linker_patches->empty());
   6483   size_t size =
   6484       method_patches_.size() +
   6485       call_patches_.size() +
   6486       relative_call_patches_.size() +
   6487       /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
   6488       boot_image_string_patches_.size() +
   6489       /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
   6490       boot_image_address_patches_.size();
   6491   linker_patches->reserve(size);
   6492   for (const auto& entry : method_patches_) {
   6493     const MethodReference& target_method = entry.first;
   6494     Literal* literal = entry.second;
   6495     DCHECK(literal->GetLabel()->IsBound());
   6496     uint32_t literal_offset = literal->GetLabel()->Position();
   6497     linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
   6498                                                        target_method.dex_file,
   6499                                                        target_method.dex_method_index));
   6500   }
   6501   for (const auto& entry : call_patches_) {
   6502     const MethodReference& target_method = entry.first;
   6503     Literal* literal = entry.second;
   6504     DCHECK(literal->GetLabel()->IsBound());
   6505     uint32_t literal_offset = literal->GetLabel()->Position();
   6506     linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
   6507                                                      target_method.dex_file,
   6508                                                      target_method.dex_method_index));
   6509   }
   6510   for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
   6511     uint32_t literal_offset = info.label.Position();
   6512     linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
   6513                                                              info.target_method.dex_file,
   6514                                                              info.target_method.dex_method_index));
   6515   }
   6516   for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
   6517     const DexFile& dex_file = info.target_dex_file;
   6518     size_t base_element_offset = info.offset_or_index;
   6519     DCHECK(info.add_pc_label.IsBound());
   6520     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
   6521     // Add MOVW patch.
   6522     DCHECK(info.movw_label.IsBound());
   6523     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
   6524     linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
   6525                                                               &dex_file,
   6526                                                               add_pc_offset,
   6527                                                               base_element_offset));
   6528     // Add MOVT patch.
   6529     DCHECK(info.movt_label.IsBound());
   6530     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
   6531     linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
   6532                                                               &dex_file,
   6533                                                               add_pc_offset,
   6534                                                               base_element_offset));
   6535   }
   6536   for (const auto& entry : boot_image_string_patches_) {
   6537     const StringReference& target_string = entry.first;
   6538     Literal* literal = entry.second;
   6539     DCHECK(literal->GetLabel()->IsBound());
   6540     uint32_t literal_offset = literal->GetLabel()->Position();
   6541     linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
   6542                                                        target_string.dex_file,
   6543                                                        target_string.string_index));
   6544   }
   6545   for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
   6546     const DexFile& dex_file = info.target_dex_file;
   6547     uint32_t string_index = info.offset_or_index;
   6548     DCHECK(info.add_pc_label.IsBound());
   6549     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
   6550     // Add MOVW patch.
   6551     DCHECK(info.movw_label.IsBound());
   6552     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
   6553     linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
   6554                                                                &dex_file,
   6555                                                                add_pc_offset,
   6556                                                                string_index));
   6557     // Add MOVT patch.
   6558     DCHECK(info.movt_label.IsBound());
   6559     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
   6560     linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
   6561                                                                &dex_file,
   6562                                                                add_pc_offset,
   6563                                                                string_index));
   6564   }
   6565   for (const auto& entry : boot_image_address_patches_) {
   6566     DCHECK(GetCompilerOptions().GetIncludePatchInformation());
   6567     Literal* literal = entry.second;
   6568     DCHECK(literal->GetLabel()->IsBound());
   6569     uint32_t literal_offset = literal->GetLabel()->Position();
   6570     linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
   6571   }
   6572 }
   6573 
   6574 Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
   6575   return map->GetOrCreate(
   6576       value,
   6577       [this, value]() { return __ NewLiteral<uint32_t>(value); });
   6578 }
   6579 
   6580 Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
   6581                                                     MethodToLiteralMap* map) {
   6582   return map->GetOrCreate(
   6583       target_method,
   6584       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
   6585 }
   6586 
   6587 Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
   6588   return DeduplicateMethodLiteral(target_method, &method_patches_);
   6589 }
   6590 
   6591 Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
   6592   return DeduplicateMethodLiteral(target_method, &call_patches_);
   6593 }
   6594 
   6595 void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
   6596   LocationSummary* locations =
   6597       new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
   6598   locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
   6599                      Location::RequiresRegister());
   6600   locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
   6601   locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
   6602   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   6603 }
   6604 
   6605 void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
   6606   LocationSummary* locations = instr->GetLocations();
   6607   Register res = locations->Out().AsRegister<Register>();
   6608   Register accumulator =
   6609       locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
   6610   Register mul_left =
   6611       locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
   6612   Register mul_right =
   6613       locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
   6614 
   6615   if (instr->GetOpKind() == HInstruction::kAdd) {
   6616     __ mla(res, mul_left, mul_right, accumulator);
   6617   } else {
   6618     __ mls(res, mul_left, mul_right, accumulator);
   6619   }
   6620 }
   6621 
   6622 void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
   6623   // Nothing to do, this should be removed during prepare for register allocator.
   6624   LOG(FATAL) << "Unreachable";
   6625 }
   6626 
   6627 void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
   6628   // Nothing to do, this should be removed during prepare for register allocator.
   6629   LOG(FATAL) << "Unreachable";
   6630 }
   6631 
   6632 // Simple implementation of packed switch - generate cascaded compare/jumps.
   6633 void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
   6634   LocationSummary* locations =
   6635       new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
   6636   locations->SetInAt(0, Location::RequiresRegister());
   6637   if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
   6638       codegen_->GetAssembler()->IsThumb()) {
   6639     locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
   6640     if (switch_instr->GetStartValue() != 0) {
   6641       locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
   6642     }
   6643   }
   6644 }
   6645 
   6646 void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
   6647   int32_t lower_bound = switch_instr->GetStartValue();
   6648   uint32_t num_entries = switch_instr->GetNumEntries();
   6649   LocationSummary* locations = switch_instr->GetLocations();
   6650   Register value_reg = locations->InAt(0).AsRegister<Register>();
   6651   HBasicBlock* default_block = switch_instr->GetDefaultBlock();
   6652 
   6653   if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
   6654     // Create a series of compare/jumps.
   6655     Register temp_reg = IP;
   6656     // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
   6657     // the immediate, because IP is used as the destination register. For the other
   6658     // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
   6659     // and they can be encoded in the instruction without making use of IP register.
   6660     __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
   6661 
   6662     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
   6663     // Jump to successors[0] if value == lower_bound.
   6664     __ b(codegen_->GetLabelOf(successors[0]), EQ);
   6665     int32_t last_index = 0;
   6666     for (; num_entries - last_index > 2; last_index += 2) {
   6667       __ AddConstantSetFlags(temp_reg, temp_reg, -2);
   6668       // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
   6669       __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
   6670       // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
   6671       __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
   6672     }
   6673     if (num_entries - last_index == 2) {
   6674       // The last missing case_value.
   6675       __ CmpConstant(temp_reg, 1);
   6676       __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
   6677     }
   6678 
   6679     // And the default for any other value.
   6680     if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
   6681       __ b(codegen_->GetLabelOf(default_block));
   6682     }
   6683   } else {
   6684     // Create a table lookup.
   6685     Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
   6686 
   6687     // Materialize a pointer to the switch table
   6688     std::vector<Label*> labels(num_entries);
   6689     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
   6690     for (uint32_t i = 0; i < num_entries; i++) {
   6691       labels[i] = codegen_->GetLabelOf(successors[i]);
   6692     }
   6693     JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
   6694 
   6695     // Remove the bias.
   6696     Register key_reg;
   6697     if (lower_bound != 0) {
   6698       key_reg = locations->GetTemp(1).AsRegister<Register>();
   6699       __ AddConstant(key_reg, value_reg, -lower_bound);
   6700     } else {
   6701       key_reg = value_reg;
   6702     }
   6703 
   6704     // Check whether the value is in the table, jump to default block if not.
   6705     __ CmpConstant(key_reg, num_entries - 1);
   6706     __ b(codegen_->GetLabelOf(default_block), Condition::HI);
   6707 
   6708     // Load the displacement from the table.
   6709     __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
   6710 
   6711     // Dispatch is a direct add to the PC (for Thumb2).
   6712     __ EmitJumpTableDispatch(table, temp_reg);
   6713   }
   6714 }
   6715 
   6716 void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
   6717   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
   6718   locations->SetOut(Location::RequiresRegister());
   6719 }
   6720 
   6721 void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
   6722   Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
   6723   CodeGeneratorARM::PcRelativePatchInfo* labels =
   6724       codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
   6725   __ BindTrackedLabel(&labels->movw_label);
   6726   __ movw(base_reg, /* placeholder */ 0u);
   6727   __ BindTrackedLabel(&labels->movt_label);
   6728   __ movt(base_reg, /* placeholder */ 0u);
   6729   __ BindTrackedLabel(&labels->add_pc_label);
   6730   __ add(base_reg, base_reg, ShifterOperand(PC));
   6731 }
   6732 
   6733 void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
   6734   if (!trg.IsValid()) {
   6735     DCHECK_EQ(type, Primitive::kPrimVoid);
   6736     return;
   6737   }
   6738 
   6739   DCHECK_NE(type, Primitive::kPrimVoid);
   6740 
   6741   Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
   6742   if (return_loc.Equals(trg)) {
   6743     return;
   6744   }
   6745 
   6746   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
   6747   //       with the last branch.
   6748   if (type == Primitive::kPrimLong) {
   6749     HParallelMove parallel_move(GetGraph()->GetArena());
   6750     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
   6751     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
   6752     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6753   } else if (type == Primitive::kPrimDouble) {
   6754     HParallelMove parallel_move(GetGraph()->GetArena());
   6755     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
   6756     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
   6757     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6758   } else {
   6759     // Let the parallel move resolver take care of all of this.
   6760     HParallelMove parallel_move(GetGraph()->GetArena());
   6761     parallel_move.AddMove(return_loc, trg, type, nullptr);
   6762     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6763   }
   6764 }
   6765 
   6766 void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
   6767   LocationSummary* locations =
   6768       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   6769   locations->SetInAt(0, Location::RequiresRegister());
   6770   locations->SetOut(Location::RequiresRegister());
   6771 }
   6772 
   6773 void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
   6774   LocationSummary* locations = instruction->GetLocations();
   6775   if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
   6776     uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
   6777         instruction->GetIndex(), kArmPointerSize).SizeValue();
   6778     __ LoadFromOffset(kLoadWord,
   6779                       locations->Out().AsRegister<Register>(),
   6780                       locations->InAt(0).AsRegister<Register>(),
   6781                       method_offset);
   6782   } else {
   6783     uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
   6784         instruction->GetIndex() % ImTable::kSize, kArmPointerSize));
   6785     __ LoadFromOffset(kLoadWord,
   6786                       locations->Out().AsRegister<Register>(),
   6787                       locations->InAt(0).AsRegister<Register>(),
   6788                       mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
   6789     __ LoadFromOffset(kLoadWord,
   6790                       locations->Out().AsRegister<Register>(),
   6791                       locations->Out().AsRegister<Register>(),
   6792                       method_offset);
   6793   }
   6794 }
   6795 
   6796 #undef __
   6797 #undef QUICK_ENTRY_POINT
   6798 
   6799 }  // namespace arm
   6800 }  // namespace art
   6801