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   uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
   1875       invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
   1876   Location receiver = locations->InAt(0);
   1877   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   1878 
   1879   // Set the hidden argument. This is safe to do this here, as R12
   1880   // won't be modified thereafter, before the `blx` (call) instruction.
   1881   DCHECK_EQ(R12, hidden_reg);
   1882   __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
   1883 
   1884   if (receiver.IsStackSlot()) {
   1885     __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
   1886     // /* HeapReference<Class> */ temp = temp->klass_
   1887     __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
   1888   } else {
   1889     // /* HeapReference<Class> */ temp = receiver->klass_
   1890     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   1891   }
   1892   codegen_->MaybeRecordImplicitNullCheck(invoke);
   1893   // Instead of simply (possibly) unpoisoning `temp` here, we should
   1894   // emit a read barrier for the previous class reference load.
   1895   // However this is not required in practice, as this is an
   1896   // intermediate/temporary reference and because the current
   1897   // concurrent copying collector keeps the from-space memory
   1898   // intact/accessible until the end of the marking phase (the
   1899   // concurrent copying collector may not in the future).
   1900   __ MaybeUnpoisonHeapReference(temp);
   1901   // temp = temp->GetImtEntryAt(method_offset);
   1902   uint32_t entry_point =
   1903       ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
   1904   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
   1905   // LR = temp->GetEntryPoint();
   1906   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
   1907   // LR();
   1908   __ blx(LR);
   1909   DCHECK(!codegen_->IsLeafMethod());
   1910   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
   1911 }
   1912 
   1913 void LocationsBuilderARM::VisitNeg(HNeg* neg) {
   1914   LocationSummary* locations =
   1915       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
   1916   switch (neg->GetResultType()) {
   1917     case Primitive::kPrimInt: {
   1918       locations->SetInAt(0, Location::RequiresRegister());
   1919       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   1920       break;
   1921     }
   1922     case Primitive::kPrimLong: {
   1923       locations->SetInAt(0, Location::RequiresRegister());
   1924       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   1925       break;
   1926     }
   1927 
   1928     case Primitive::kPrimFloat:
   1929     case Primitive::kPrimDouble:
   1930       locations->SetInAt(0, Location::RequiresFpuRegister());
   1931       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   1932       break;
   1933 
   1934     default:
   1935       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
   1936   }
   1937 }
   1938 
   1939 void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
   1940   LocationSummary* locations = neg->GetLocations();
   1941   Location out = locations->Out();
   1942   Location in = locations->InAt(0);
   1943   switch (neg->GetResultType()) {
   1944     case Primitive::kPrimInt:
   1945       DCHECK(in.IsRegister());
   1946       __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
   1947       break;
   1948 
   1949     case Primitive::kPrimLong:
   1950       DCHECK(in.IsRegisterPair());
   1951       // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
   1952       __ rsbs(out.AsRegisterPairLow<Register>(),
   1953               in.AsRegisterPairLow<Register>(),
   1954               ShifterOperand(0));
   1955       // We cannot emit an RSC (Reverse Subtract with Carry)
   1956       // instruction here, as it does not exist in the Thumb-2
   1957       // instruction set.  We use the following approach
   1958       // using SBC and SUB instead.
   1959       //
   1960       // out.hi = -C
   1961       __ sbc(out.AsRegisterPairHigh<Register>(),
   1962              out.AsRegisterPairHigh<Register>(),
   1963              ShifterOperand(out.AsRegisterPairHigh<Register>()));
   1964       // out.hi = out.hi - in.hi
   1965       __ sub(out.AsRegisterPairHigh<Register>(),
   1966              out.AsRegisterPairHigh<Register>(),
   1967              ShifterOperand(in.AsRegisterPairHigh<Register>()));
   1968       break;
   1969 
   1970     case Primitive::kPrimFloat:
   1971       DCHECK(in.IsFpuRegister());
   1972       __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
   1973       break;
   1974 
   1975     case Primitive::kPrimDouble:
   1976       DCHECK(in.IsFpuRegisterPair());
   1977       __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   1978                FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   1979       break;
   1980 
   1981     default:
   1982       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
   1983   }
   1984 }
   1985 
   1986 void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
   1987   Primitive::Type result_type = conversion->GetResultType();
   1988   Primitive::Type input_type = conversion->GetInputType();
   1989   DCHECK_NE(result_type, input_type);
   1990 
   1991   // The float-to-long, double-to-long and long-to-float type conversions
   1992   // rely on a call to the runtime.
   1993   LocationSummary::CallKind call_kind =
   1994       (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
   1995         && result_type == Primitive::kPrimLong)
   1996        || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
   1997       ? LocationSummary::kCall
   1998       : LocationSummary::kNoCall;
   1999   LocationSummary* locations =
   2000       new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
   2001 
   2002   // The Java language does not allow treating boolean as an integral type but
   2003   // our bit representation makes it safe.
   2004 
   2005   switch (result_type) {
   2006     case Primitive::kPrimByte:
   2007       switch (input_type) {
   2008         case Primitive::kPrimLong:
   2009           // Type conversion from long to byte is a result of code transformations.
   2010         case Primitive::kPrimBoolean:
   2011           // Boolean input is a result of code transformations.
   2012         case Primitive::kPrimShort:
   2013         case Primitive::kPrimInt:
   2014         case Primitive::kPrimChar:
   2015           // Processing a Dex `int-to-byte' instruction.
   2016           locations->SetInAt(0, Location::RequiresRegister());
   2017           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2018           break;
   2019 
   2020         default:
   2021           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2022                      << " to " << result_type;
   2023       }
   2024       break;
   2025 
   2026     case Primitive::kPrimShort:
   2027       switch (input_type) {
   2028         case Primitive::kPrimLong:
   2029           // Type conversion from long to short is a result of code transformations.
   2030         case Primitive::kPrimBoolean:
   2031           // Boolean input is a result of code transformations.
   2032         case Primitive::kPrimByte:
   2033         case Primitive::kPrimInt:
   2034         case Primitive::kPrimChar:
   2035           // Processing a Dex `int-to-short' instruction.
   2036           locations->SetInAt(0, Location::RequiresRegister());
   2037           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2038           break;
   2039 
   2040         default:
   2041           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2042                      << " to " << result_type;
   2043       }
   2044       break;
   2045 
   2046     case Primitive::kPrimInt:
   2047       switch (input_type) {
   2048         case Primitive::kPrimLong:
   2049           // Processing a Dex `long-to-int' instruction.
   2050           locations->SetInAt(0, Location::Any());
   2051           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2052           break;
   2053 
   2054         case Primitive::kPrimFloat:
   2055           // Processing a Dex `float-to-int' instruction.
   2056           locations->SetInAt(0, Location::RequiresFpuRegister());
   2057           locations->SetOut(Location::RequiresRegister());
   2058           locations->AddTemp(Location::RequiresFpuRegister());
   2059           break;
   2060 
   2061         case Primitive::kPrimDouble:
   2062           // Processing a Dex `double-to-int' instruction.
   2063           locations->SetInAt(0, Location::RequiresFpuRegister());
   2064           locations->SetOut(Location::RequiresRegister());
   2065           locations->AddTemp(Location::RequiresFpuRegister());
   2066           break;
   2067 
   2068         default:
   2069           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2070                      << " to " << result_type;
   2071       }
   2072       break;
   2073 
   2074     case Primitive::kPrimLong:
   2075       switch (input_type) {
   2076         case Primitive::kPrimBoolean:
   2077           // Boolean input is a result of code transformations.
   2078         case Primitive::kPrimByte:
   2079         case Primitive::kPrimShort:
   2080         case Primitive::kPrimInt:
   2081         case Primitive::kPrimChar:
   2082           // Processing a Dex `int-to-long' instruction.
   2083           locations->SetInAt(0, Location::RequiresRegister());
   2084           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2085           break;
   2086 
   2087         case Primitive::kPrimFloat: {
   2088           // Processing a Dex `float-to-long' instruction.
   2089           InvokeRuntimeCallingConvention calling_convention;
   2090           locations->SetInAt(0, Location::FpuRegisterLocation(
   2091               calling_convention.GetFpuRegisterAt(0)));
   2092           locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2093           break;
   2094         }
   2095 
   2096         case Primitive::kPrimDouble: {
   2097           // Processing a Dex `double-to-long' instruction.
   2098           InvokeRuntimeCallingConvention calling_convention;
   2099           locations->SetInAt(0, Location::FpuRegisterPairLocation(
   2100               calling_convention.GetFpuRegisterAt(0),
   2101               calling_convention.GetFpuRegisterAt(1)));
   2102           locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2103           break;
   2104         }
   2105 
   2106         default:
   2107           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2108                      << " to " << result_type;
   2109       }
   2110       break;
   2111 
   2112     case Primitive::kPrimChar:
   2113       switch (input_type) {
   2114         case Primitive::kPrimLong:
   2115           // Type conversion from long to char is a result of code transformations.
   2116         case Primitive::kPrimBoolean:
   2117           // Boolean input is a result of code transformations.
   2118         case Primitive::kPrimByte:
   2119         case Primitive::kPrimShort:
   2120         case Primitive::kPrimInt:
   2121           // Processing a Dex `int-to-char' instruction.
   2122           locations->SetInAt(0, Location::RequiresRegister());
   2123           locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2124           break;
   2125 
   2126         default:
   2127           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2128                      << " to " << result_type;
   2129       }
   2130       break;
   2131 
   2132     case Primitive::kPrimFloat:
   2133       switch (input_type) {
   2134         case Primitive::kPrimBoolean:
   2135           // Boolean input is a result of code transformations.
   2136         case Primitive::kPrimByte:
   2137         case Primitive::kPrimShort:
   2138         case Primitive::kPrimInt:
   2139         case Primitive::kPrimChar:
   2140           // Processing a Dex `int-to-float' instruction.
   2141           locations->SetInAt(0, Location::RequiresRegister());
   2142           locations->SetOut(Location::RequiresFpuRegister());
   2143           break;
   2144 
   2145         case Primitive::kPrimLong: {
   2146           // Processing a Dex `long-to-float' instruction.
   2147           InvokeRuntimeCallingConvention calling_convention;
   2148           locations->SetInAt(0, Location::RegisterPairLocation(
   2149               calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2150           locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2151           break;
   2152         }
   2153 
   2154         case Primitive::kPrimDouble:
   2155           // Processing a Dex `double-to-float' instruction.
   2156           locations->SetInAt(0, Location::RequiresFpuRegister());
   2157           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2158           break;
   2159 
   2160         default:
   2161           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2162                      << " to " << result_type;
   2163       };
   2164       break;
   2165 
   2166     case Primitive::kPrimDouble:
   2167       switch (input_type) {
   2168         case Primitive::kPrimBoolean:
   2169           // Boolean input is a result of code transformations.
   2170         case Primitive::kPrimByte:
   2171         case Primitive::kPrimShort:
   2172         case Primitive::kPrimInt:
   2173         case Primitive::kPrimChar:
   2174           // Processing a Dex `int-to-double' instruction.
   2175           locations->SetInAt(0, Location::RequiresRegister());
   2176           locations->SetOut(Location::RequiresFpuRegister());
   2177           break;
   2178 
   2179         case Primitive::kPrimLong:
   2180           // Processing a Dex `long-to-double' instruction.
   2181           locations->SetInAt(0, Location::RequiresRegister());
   2182           locations->SetOut(Location::RequiresFpuRegister());
   2183           locations->AddTemp(Location::RequiresFpuRegister());
   2184           locations->AddTemp(Location::RequiresFpuRegister());
   2185           break;
   2186 
   2187         case Primitive::kPrimFloat:
   2188           // Processing a Dex `float-to-double' instruction.
   2189           locations->SetInAt(0, Location::RequiresFpuRegister());
   2190           locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2191           break;
   2192 
   2193         default:
   2194           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2195                      << " to " << result_type;
   2196       };
   2197       break;
   2198 
   2199     default:
   2200       LOG(FATAL) << "Unexpected type conversion from " << input_type
   2201                  << " to " << result_type;
   2202   }
   2203 }
   2204 
   2205 void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
   2206   LocationSummary* locations = conversion->GetLocations();
   2207   Location out = locations->Out();
   2208   Location in = locations->InAt(0);
   2209   Primitive::Type result_type = conversion->GetResultType();
   2210   Primitive::Type input_type = conversion->GetInputType();
   2211   DCHECK_NE(result_type, input_type);
   2212   switch (result_type) {
   2213     case Primitive::kPrimByte:
   2214       switch (input_type) {
   2215         case Primitive::kPrimLong:
   2216           // Type conversion from long to byte is a result of code transformations.
   2217           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
   2218           break;
   2219         case Primitive::kPrimBoolean:
   2220           // Boolean input is a result of code transformations.
   2221         case Primitive::kPrimShort:
   2222         case Primitive::kPrimInt:
   2223         case Primitive::kPrimChar:
   2224           // Processing a Dex `int-to-byte' instruction.
   2225           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
   2226           break;
   2227 
   2228         default:
   2229           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2230                      << " to " << result_type;
   2231       }
   2232       break;
   2233 
   2234     case Primitive::kPrimShort:
   2235       switch (input_type) {
   2236         case Primitive::kPrimLong:
   2237           // Type conversion from long to short is a result of code transformations.
   2238           __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
   2239           break;
   2240         case Primitive::kPrimBoolean:
   2241           // Boolean input is a result of code transformations.
   2242         case Primitive::kPrimByte:
   2243         case Primitive::kPrimInt:
   2244         case Primitive::kPrimChar:
   2245           // Processing a Dex `int-to-short' instruction.
   2246           __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
   2247           break;
   2248 
   2249         default:
   2250           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2251                      << " to " << result_type;
   2252       }
   2253       break;
   2254 
   2255     case Primitive::kPrimInt:
   2256       switch (input_type) {
   2257         case Primitive::kPrimLong:
   2258           // Processing a Dex `long-to-int' instruction.
   2259           DCHECK(out.IsRegister());
   2260           if (in.IsRegisterPair()) {
   2261             __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
   2262           } else if (in.IsDoubleStackSlot()) {
   2263             __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
   2264           } else {
   2265             DCHECK(in.IsConstant());
   2266             DCHECK(in.GetConstant()->IsLongConstant());
   2267             int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
   2268             __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
   2269           }
   2270           break;
   2271 
   2272         case Primitive::kPrimFloat: {
   2273           // Processing a Dex `float-to-int' instruction.
   2274           SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2275           __ vmovs(temp, in.AsFpuRegister<SRegister>());
   2276           __ vcvtis(temp, temp);
   2277           __ vmovrs(out.AsRegister<Register>(), temp);
   2278           break;
   2279         }
   2280 
   2281         case Primitive::kPrimDouble: {
   2282           // Processing a Dex `double-to-int' instruction.
   2283           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2284           DRegister temp_d = FromLowSToD(temp_s);
   2285           __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   2286           __ vcvtid(temp_s, temp_d);
   2287           __ vmovrs(out.AsRegister<Register>(), temp_s);
   2288           break;
   2289         }
   2290 
   2291         default:
   2292           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2293                      << " to " << result_type;
   2294       }
   2295       break;
   2296 
   2297     case Primitive::kPrimLong:
   2298       switch (input_type) {
   2299         case Primitive::kPrimBoolean:
   2300           // Boolean input is a result of code transformations.
   2301         case Primitive::kPrimByte:
   2302         case Primitive::kPrimShort:
   2303         case Primitive::kPrimInt:
   2304         case Primitive::kPrimChar:
   2305           // Processing a Dex `int-to-long' instruction.
   2306           DCHECK(out.IsRegisterPair());
   2307           DCHECK(in.IsRegister());
   2308           __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
   2309           // Sign extension.
   2310           __ Asr(out.AsRegisterPairHigh<Register>(),
   2311                  out.AsRegisterPairLow<Register>(),
   2312                  31);
   2313           break;
   2314 
   2315         case Primitive::kPrimFloat:
   2316           // Processing a Dex `float-to-long' instruction.
   2317           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
   2318                                   conversion,
   2319                                   conversion->GetDexPc(),
   2320                                   nullptr);
   2321           CheckEntrypointTypes<kQuickF2l, int64_t, float>();
   2322           break;
   2323 
   2324         case Primitive::kPrimDouble:
   2325           // Processing a Dex `double-to-long' instruction.
   2326           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
   2327                                   conversion,
   2328                                   conversion->GetDexPc(),
   2329                                   nullptr);
   2330           CheckEntrypointTypes<kQuickD2l, int64_t, double>();
   2331           break;
   2332 
   2333         default:
   2334           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2335                      << " to " << result_type;
   2336       }
   2337       break;
   2338 
   2339     case Primitive::kPrimChar:
   2340       switch (input_type) {
   2341         case Primitive::kPrimLong:
   2342           // Type conversion from long to char is a result of code transformations.
   2343           __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
   2344           break;
   2345         case Primitive::kPrimBoolean:
   2346           // Boolean input is a result of code transformations.
   2347         case Primitive::kPrimByte:
   2348         case Primitive::kPrimShort:
   2349         case Primitive::kPrimInt:
   2350           // Processing a Dex `int-to-char' instruction.
   2351           __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
   2352           break;
   2353 
   2354         default:
   2355           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2356                      << " to " << result_type;
   2357       }
   2358       break;
   2359 
   2360     case Primitive::kPrimFloat:
   2361       switch (input_type) {
   2362         case Primitive::kPrimBoolean:
   2363           // Boolean input is a result of code transformations.
   2364         case Primitive::kPrimByte:
   2365         case Primitive::kPrimShort:
   2366         case Primitive::kPrimInt:
   2367         case Primitive::kPrimChar: {
   2368           // Processing a Dex `int-to-float' instruction.
   2369           __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
   2370           __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
   2371           break;
   2372         }
   2373 
   2374         case Primitive::kPrimLong:
   2375           // Processing a Dex `long-to-float' instruction.
   2376           codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
   2377                                   conversion,
   2378                                   conversion->GetDexPc(),
   2379                                   nullptr);
   2380           CheckEntrypointTypes<kQuickL2f, float, int64_t>();
   2381           break;
   2382 
   2383         case Primitive::kPrimDouble:
   2384           // Processing a Dex `double-to-float' instruction.
   2385           __ vcvtsd(out.AsFpuRegister<SRegister>(),
   2386                     FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
   2387           break;
   2388 
   2389         default:
   2390           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2391                      << " to " << result_type;
   2392       };
   2393       break;
   2394 
   2395     case Primitive::kPrimDouble:
   2396       switch (input_type) {
   2397         case Primitive::kPrimBoolean:
   2398           // Boolean input is a result of code transformations.
   2399         case Primitive::kPrimByte:
   2400         case Primitive::kPrimShort:
   2401         case Primitive::kPrimInt:
   2402         case Primitive::kPrimChar: {
   2403           // Processing a Dex `int-to-double' instruction.
   2404           __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
   2405           __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2406                     out.AsFpuRegisterPairLow<SRegister>());
   2407           break;
   2408         }
   2409 
   2410         case Primitive::kPrimLong: {
   2411           // Processing a Dex `long-to-double' instruction.
   2412           Register low = in.AsRegisterPairLow<Register>();
   2413           Register high = in.AsRegisterPairHigh<Register>();
   2414           SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
   2415           DRegister out_d = FromLowSToD(out_s);
   2416           SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
   2417           DRegister temp_d = FromLowSToD(temp_s);
   2418           SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
   2419           DRegister constant_d = FromLowSToD(constant_s);
   2420 
   2421           // temp_d = int-to-double(high)
   2422           __ vmovsr(temp_s, high);
   2423           __ vcvtdi(temp_d, temp_s);
   2424           // constant_d = k2Pow32EncodingForDouble
   2425           __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
   2426           // out_d = unsigned-to-double(low)
   2427           __ vmovsr(out_s, low);
   2428           __ vcvtdu(out_d, out_s);
   2429           // out_d += temp_d * constant_d
   2430           __ vmlad(out_d, temp_d, constant_d);
   2431           break;
   2432         }
   2433 
   2434         case Primitive::kPrimFloat:
   2435           // Processing a Dex `float-to-double' instruction.
   2436           __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2437                     in.AsFpuRegister<SRegister>());
   2438           break;
   2439 
   2440         default:
   2441           LOG(FATAL) << "Unexpected type conversion from " << input_type
   2442                      << " to " << result_type;
   2443       };
   2444       break;
   2445 
   2446     default:
   2447       LOG(FATAL) << "Unexpected type conversion from " << input_type
   2448                  << " to " << result_type;
   2449   }
   2450 }
   2451 
   2452 void LocationsBuilderARM::VisitAdd(HAdd* add) {
   2453   LocationSummary* locations =
   2454       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   2455   switch (add->GetResultType()) {
   2456     case Primitive::kPrimInt: {
   2457       locations->SetInAt(0, Location::RequiresRegister());
   2458       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
   2459       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2460       break;
   2461     }
   2462 
   2463     case Primitive::kPrimLong: {
   2464       locations->SetInAt(0, Location::RequiresRegister());
   2465       locations->SetInAt(1, Location::RequiresRegister());
   2466       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2467       break;
   2468     }
   2469 
   2470     case Primitive::kPrimFloat:
   2471     case Primitive::kPrimDouble: {
   2472       locations->SetInAt(0, Location::RequiresFpuRegister());
   2473       locations->SetInAt(1, Location::RequiresFpuRegister());
   2474       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2475       break;
   2476     }
   2477 
   2478     default:
   2479       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   2480   }
   2481 }
   2482 
   2483 void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
   2484   LocationSummary* locations = add->GetLocations();
   2485   Location out = locations->Out();
   2486   Location first = locations->InAt(0);
   2487   Location second = locations->InAt(1);
   2488   switch (add->GetResultType()) {
   2489     case Primitive::kPrimInt:
   2490       if (second.IsRegister()) {
   2491         __ add(out.AsRegister<Register>(),
   2492                first.AsRegister<Register>(),
   2493                ShifterOperand(second.AsRegister<Register>()));
   2494       } else {
   2495         __ AddConstant(out.AsRegister<Register>(),
   2496                        first.AsRegister<Register>(),
   2497                        second.GetConstant()->AsIntConstant()->GetValue());
   2498       }
   2499       break;
   2500 
   2501     case Primitive::kPrimLong: {
   2502       DCHECK(second.IsRegisterPair());
   2503       __ adds(out.AsRegisterPairLow<Register>(),
   2504               first.AsRegisterPairLow<Register>(),
   2505               ShifterOperand(second.AsRegisterPairLow<Register>()));
   2506       __ adc(out.AsRegisterPairHigh<Register>(),
   2507              first.AsRegisterPairHigh<Register>(),
   2508              ShifterOperand(second.AsRegisterPairHigh<Register>()));
   2509       break;
   2510     }
   2511 
   2512     case Primitive::kPrimFloat:
   2513       __ vadds(out.AsFpuRegister<SRegister>(),
   2514                first.AsFpuRegister<SRegister>(),
   2515                second.AsFpuRegister<SRegister>());
   2516       break;
   2517 
   2518     case Primitive::kPrimDouble:
   2519       __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2520                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2521                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2522       break;
   2523 
   2524     default:
   2525       LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   2526   }
   2527 }
   2528 
   2529 void LocationsBuilderARM::VisitSub(HSub* sub) {
   2530   LocationSummary* locations =
   2531       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   2532   switch (sub->GetResultType()) {
   2533     case Primitive::kPrimInt: {
   2534       locations->SetInAt(0, Location::RequiresRegister());
   2535       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
   2536       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2537       break;
   2538     }
   2539 
   2540     case Primitive::kPrimLong: {
   2541       locations->SetInAt(0, Location::RequiresRegister());
   2542       locations->SetInAt(1, Location::RequiresRegister());
   2543       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2544       break;
   2545     }
   2546     case Primitive::kPrimFloat:
   2547     case Primitive::kPrimDouble: {
   2548       locations->SetInAt(0, Location::RequiresFpuRegister());
   2549       locations->SetInAt(1, Location::RequiresFpuRegister());
   2550       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2551       break;
   2552     }
   2553     default:
   2554       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   2555   }
   2556 }
   2557 
   2558 void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
   2559   LocationSummary* locations = sub->GetLocations();
   2560   Location out = locations->Out();
   2561   Location first = locations->InAt(0);
   2562   Location second = locations->InAt(1);
   2563   switch (sub->GetResultType()) {
   2564     case Primitive::kPrimInt: {
   2565       if (second.IsRegister()) {
   2566         __ sub(out.AsRegister<Register>(),
   2567                first.AsRegister<Register>(),
   2568                ShifterOperand(second.AsRegister<Register>()));
   2569       } else {
   2570         __ AddConstant(out.AsRegister<Register>(),
   2571                        first.AsRegister<Register>(),
   2572                        -second.GetConstant()->AsIntConstant()->GetValue());
   2573       }
   2574       break;
   2575     }
   2576 
   2577     case Primitive::kPrimLong: {
   2578       DCHECK(second.IsRegisterPair());
   2579       __ subs(out.AsRegisterPairLow<Register>(),
   2580               first.AsRegisterPairLow<Register>(),
   2581               ShifterOperand(second.AsRegisterPairLow<Register>()));
   2582       __ sbc(out.AsRegisterPairHigh<Register>(),
   2583              first.AsRegisterPairHigh<Register>(),
   2584              ShifterOperand(second.AsRegisterPairHigh<Register>()));
   2585       break;
   2586     }
   2587 
   2588     case Primitive::kPrimFloat: {
   2589       __ vsubs(out.AsFpuRegister<SRegister>(),
   2590                first.AsFpuRegister<SRegister>(),
   2591                second.AsFpuRegister<SRegister>());
   2592       break;
   2593     }
   2594 
   2595     case Primitive::kPrimDouble: {
   2596       __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2597                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2598                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2599       break;
   2600     }
   2601 
   2602 
   2603     default:
   2604       LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   2605   }
   2606 }
   2607 
   2608 void LocationsBuilderARM::VisitMul(HMul* mul) {
   2609   LocationSummary* locations =
   2610       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
   2611   switch (mul->GetResultType()) {
   2612     case Primitive::kPrimInt:
   2613     case Primitive::kPrimLong:  {
   2614       locations->SetInAt(0, Location::RequiresRegister());
   2615       locations->SetInAt(1, Location::RequiresRegister());
   2616       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2617       break;
   2618     }
   2619 
   2620     case Primitive::kPrimFloat:
   2621     case Primitive::kPrimDouble: {
   2622       locations->SetInAt(0, Location::RequiresFpuRegister());
   2623       locations->SetInAt(1, Location::RequiresFpuRegister());
   2624       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2625       break;
   2626     }
   2627 
   2628     default:
   2629       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   2630   }
   2631 }
   2632 
   2633 void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
   2634   LocationSummary* locations = mul->GetLocations();
   2635   Location out = locations->Out();
   2636   Location first = locations->InAt(0);
   2637   Location second = locations->InAt(1);
   2638   switch (mul->GetResultType()) {
   2639     case Primitive::kPrimInt: {
   2640       __ mul(out.AsRegister<Register>(),
   2641              first.AsRegister<Register>(),
   2642              second.AsRegister<Register>());
   2643       break;
   2644     }
   2645     case Primitive::kPrimLong: {
   2646       Register out_hi = out.AsRegisterPairHigh<Register>();
   2647       Register out_lo = out.AsRegisterPairLow<Register>();
   2648       Register in1_hi = first.AsRegisterPairHigh<Register>();
   2649       Register in1_lo = first.AsRegisterPairLow<Register>();
   2650       Register in2_hi = second.AsRegisterPairHigh<Register>();
   2651       Register in2_lo = second.AsRegisterPairLow<Register>();
   2652 
   2653       // Extra checks to protect caused by the existence of R1_R2.
   2654       // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
   2655       // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
   2656       DCHECK_NE(out_hi, in1_lo);
   2657       DCHECK_NE(out_hi, in2_lo);
   2658 
   2659       // input: in1 - 64 bits, in2 - 64 bits
   2660       // output: out
   2661       // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
   2662       // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
   2663       // parts: out.lo = (in1.lo * in2.lo)[31:0]
   2664 
   2665       // IP <- in1.lo * in2.hi
   2666       __ mul(IP, in1_lo, in2_hi);
   2667       // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
   2668       __ mla(out_hi, in1_hi, in2_lo, IP);
   2669       // out.lo <- (in1.lo * in2.lo)[31:0];
   2670       __ umull(out_lo, IP, in1_lo, in2_lo);
   2671       // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
   2672       __ add(out_hi, out_hi, ShifterOperand(IP));
   2673       break;
   2674     }
   2675 
   2676     case Primitive::kPrimFloat: {
   2677       __ vmuls(out.AsFpuRegister<SRegister>(),
   2678                first.AsFpuRegister<SRegister>(),
   2679                second.AsFpuRegister<SRegister>());
   2680       break;
   2681     }
   2682 
   2683     case Primitive::kPrimDouble: {
   2684       __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2685                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2686                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2687       break;
   2688     }
   2689 
   2690     default:
   2691       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   2692   }
   2693 }
   2694 
   2695 void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
   2696   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2697   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2698 
   2699   LocationSummary* locations = instruction->GetLocations();
   2700   Location second = locations->InAt(1);
   2701   DCHECK(second.IsConstant());
   2702 
   2703   Register out = locations->Out().AsRegister<Register>();
   2704   Register dividend = locations->InAt(0).AsRegister<Register>();
   2705   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2706   DCHECK(imm == 1 || imm == -1);
   2707 
   2708   if (instruction->IsRem()) {
   2709     __ LoadImmediate(out, 0);
   2710   } else {
   2711     if (imm == 1) {
   2712       __ Mov(out, dividend);
   2713     } else {
   2714       __ rsb(out, dividend, ShifterOperand(0));
   2715     }
   2716   }
   2717 }
   2718 
   2719 void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
   2720   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2721   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2722 
   2723   LocationSummary* locations = instruction->GetLocations();
   2724   Location second = locations->InAt(1);
   2725   DCHECK(second.IsConstant());
   2726 
   2727   Register out = locations->Out().AsRegister<Register>();
   2728   Register dividend = locations->InAt(0).AsRegister<Register>();
   2729   Register temp = locations->GetTemp(0).AsRegister<Register>();
   2730   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2731   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
   2732   int ctz_imm = CTZ(abs_imm);
   2733 
   2734   if (ctz_imm == 1) {
   2735     __ Lsr(temp, dividend, 32 - ctz_imm);
   2736   } else {
   2737     __ Asr(temp, dividend, 31);
   2738     __ Lsr(temp, temp, 32 - ctz_imm);
   2739   }
   2740   __ add(out, temp, ShifterOperand(dividend));
   2741 
   2742   if (instruction->IsDiv()) {
   2743     __ Asr(out, out, ctz_imm);
   2744     if (imm < 0) {
   2745       __ rsb(out, out, ShifterOperand(0));
   2746     }
   2747   } else {
   2748     __ ubfx(out, out, 0, ctz_imm);
   2749     __ sub(out, out, ShifterOperand(temp));
   2750   }
   2751 }
   2752 
   2753 void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
   2754   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2755   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2756 
   2757   LocationSummary* locations = instruction->GetLocations();
   2758   Location second = locations->InAt(1);
   2759   DCHECK(second.IsConstant());
   2760 
   2761   Register out = locations->Out().AsRegister<Register>();
   2762   Register dividend = locations->InAt(0).AsRegister<Register>();
   2763   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
   2764   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
   2765   int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2766 
   2767   int64_t magic;
   2768   int shift;
   2769   CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
   2770 
   2771   __ LoadImmediate(temp1, magic);
   2772   __ smull(temp2, temp1, dividend, temp1);
   2773 
   2774   if (imm > 0 && magic < 0) {
   2775     __ add(temp1, temp1, ShifterOperand(dividend));
   2776   } else if (imm < 0 && magic > 0) {
   2777     __ sub(temp1, temp1, ShifterOperand(dividend));
   2778   }
   2779 
   2780   if (shift != 0) {
   2781     __ Asr(temp1, temp1, shift);
   2782   }
   2783 
   2784   if (instruction->IsDiv()) {
   2785     __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
   2786   } else {
   2787     __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
   2788     // TODO: Strength reduction for mls.
   2789     __ LoadImmediate(temp2, imm);
   2790     __ mls(out, temp1, temp2, dividend);
   2791   }
   2792 }
   2793 
   2794 void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
   2795   DCHECK(instruction->IsDiv() || instruction->IsRem());
   2796   DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
   2797 
   2798   LocationSummary* locations = instruction->GetLocations();
   2799   Location second = locations->InAt(1);
   2800   DCHECK(second.IsConstant());
   2801 
   2802   int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
   2803   if (imm == 0) {
   2804     // Do not generate anything. DivZeroCheck would prevent any code to be executed.
   2805   } else if (imm == 1 || imm == -1) {
   2806     DivRemOneOrMinusOne(instruction);
   2807   } else if (IsPowerOfTwo(AbsOrMin(imm))) {
   2808     DivRemByPowerOfTwo(instruction);
   2809   } else {
   2810     DCHECK(imm <= -2 || imm >= 2);
   2811     GenerateDivRemWithAnyConstant(instruction);
   2812   }
   2813 }
   2814 
   2815 void LocationsBuilderARM::VisitDiv(HDiv* div) {
   2816   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   2817   if (div->GetResultType() == Primitive::kPrimLong) {
   2818     // pLdiv runtime call.
   2819     call_kind = LocationSummary::kCall;
   2820   } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
   2821     // sdiv will be replaced by other instruction sequence.
   2822   } else if (div->GetResultType() == Primitive::kPrimInt &&
   2823              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2824     // pIdivmod runtime call.
   2825     call_kind = LocationSummary::kCall;
   2826   }
   2827 
   2828   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
   2829 
   2830   switch (div->GetResultType()) {
   2831     case Primitive::kPrimInt: {
   2832       if (div->InputAt(1)->IsConstant()) {
   2833         locations->SetInAt(0, Location::RequiresRegister());
   2834         locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
   2835         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2836         int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
   2837         if (value == 1 || value == 0 || value == -1) {
   2838           // No temp register required.
   2839         } else {
   2840           locations->AddTemp(Location::RequiresRegister());
   2841           if (!IsPowerOfTwo(AbsOrMin(value))) {
   2842             locations->AddTemp(Location::RequiresRegister());
   2843           }
   2844         }
   2845       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2846         locations->SetInAt(0, Location::RequiresRegister());
   2847         locations->SetInAt(1, Location::RequiresRegister());
   2848         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2849       } else {
   2850         InvokeRuntimeCallingConvention calling_convention;
   2851         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2852         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2853         // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
   2854         //       we only need the former.
   2855         locations->SetOut(Location::RegisterLocation(R0));
   2856       }
   2857       break;
   2858     }
   2859     case Primitive::kPrimLong: {
   2860       InvokeRuntimeCallingConvention calling_convention;
   2861       locations->SetInAt(0, Location::RegisterPairLocation(
   2862           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2863       locations->SetInAt(1, Location::RegisterPairLocation(
   2864           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
   2865       locations->SetOut(Location::RegisterPairLocation(R0, R1));
   2866       break;
   2867     }
   2868     case Primitive::kPrimFloat:
   2869     case Primitive::kPrimDouble: {
   2870       locations->SetInAt(0, Location::RequiresFpuRegister());
   2871       locations->SetInAt(1, Location::RequiresFpuRegister());
   2872       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   2873       break;
   2874     }
   2875 
   2876     default:
   2877       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
   2878   }
   2879 }
   2880 
   2881 void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
   2882   LocationSummary* locations = div->GetLocations();
   2883   Location out = locations->Out();
   2884   Location first = locations->InAt(0);
   2885   Location second = locations->InAt(1);
   2886 
   2887   switch (div->GetResultType()) {
   2888     case Primitive::kPrimInt: {
   2889       if (second.IsConstant()) {
   2890         GenerateDivRemConstantIntegral(div);
   2891       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2892         __ sdiv(out.AsRegister<Register>(),
   2893                 first.AsRegister<Register>(),
   2894                 second.AsRegister<Register>());
   2895       } else {
   2896         InvokeRuntimeCallingConvention calling_convention;
   2897         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
   2898         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
   2899         DCHECK_EQ(R0, out.AsRegister<Register>());
   2900 
   2901         codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
   2902         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
   2903       }
   2904       break;
   2905     }
   2906 
   2907     case Primitive::kPrimLong: {
   2908       InvokeRuntimeCallingConvention calling_convention;
   2909       DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
   2910       DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
   2911       DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
   2912       DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
   2913       DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
   2914       DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
   2915 
   2916       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
   2917       CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
   2918       break;
   2919     }
   2920 
   2921     case Primitive::kPrimFloat: {
   2922       __ vdivs(out.AsFpuRegister<SRegister>(),
   2923                first.AsFpuRegister<SRegister>(),
   2924                second.AsFpuRegister<SRegister>());
   2925       break;
   2926     }
   2927 
   2928     case Primitive::kPrimDouble: {
   2929       __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
   2930                FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
   2931                FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
   2932       break;
   2933     }
   2934 
   2935     default:
   2936       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
   2937   }
   2938 }
   2939 
   2940 void LocationsBuilderARM::VisitRem(HRem* rem) {
   2941   Primitive::Type type = rem->GetResultType();
   2942 
   2943   // Most remainders are implemented in the runtime.
   2944   LocationSummary::CallKind call_kind = LocationSummary::kCall;
   2945   if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
   2946     // sdiv will be replaced by other instruction sequence.
   2947     call_kind = LocationSummary::kNoCall;
   2948   } else if ((rem->GetResultType() == Primitive::kPrimInt)
   2949              && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2950     // Have hardware divide instruction for int, do it with three instructions.
   2951     call_kind = LocationSummary::kNoCall;
   2952   }
   2953 
   2954   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
   2955 
   2956   switch (type) {
   2957     case Primitive::kPrimInt: {
   2958       if (rem->InputAt(1)->IsConstant()) {
   2959         locations->SetInAt(0, Location::RequiresRegister());
   2960         locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
   2961         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2962         int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
   2963         if (value == 1 || value == 0 || value == -1) {
   2964           // No temp register required.
   2965         } else {
   2966           locations->AddTemp(Location::RequiresRegister());
   2967           if (!IsPowerOfTwo(AbsOrMin(value))) {
   2968             locations->AddTemp(Location::RequiresRegister());
   2969           }
   2970         }
   2971       } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   2972         locations->SetInAt(0, Location::RequiresRegister());
   2973         locations->SetInAt(1, Location::RequiresRegister());
   2974         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   2975         locations->AddTemp(Location::RequiresRegister());
   2976       } else {
   2977         InvokeRuntimeCallingConvention calling_convention;
   2978         locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2979         locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2980         // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
   2981         //       we only need the latter.
   2982         locations->SetOut(Location::RegisterLocation(R1));
   2983       }
   2984       break;
   2985     }
   2986     case Primitive::kPrimLong: {
   2987       InvokeRuntimeCallingConvention calling_convention;
   2988       locations->SetInAt(0, Location::RegisterPairLocation(
   2989           calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
   2990       locations->SetInAt(1, Location::RegisterPairLocation(
   2991           calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
   2992       // The runtime helper puts the output in R2,R3.
   2993       locations->SetOut(Location::RegisterPairLocation(R2, R3));
   2994       break;
   2995     }
   2996     case Primitive::kPrimFloat: {
   2997       InvokeRuntimeCallingConvention calling_convention;
   2998       locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2999       locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
   3000       locations->SetOut(Location::FpuRegisterLocation(S0));
   3001       break;
   3002     }
   3003 
   3004     case Primitive::kPrimDouble: {
   3005       InvokeRuntimeCallingConvention calling_convention;
   3006       locations->SetInAt(0, Location::FpuRegisterPairLocation(
   3007           calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
   3008       locations->SetInAt(1, Location::FpuRegisterPairLocation(
   3009           calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
   3010       locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
   3011       break;
   3012     }
   3013 
   3014     default:
   3015       LOG(FATAL) << "Unexpected rem type " << type;
   3016   }
   3017 }
   3018 
   3019 void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
   3020   LocationSummary* locations = rem->GetLocations();
   3021   Location out = locations->Out();
   3022   Location first = locations->InAt(0);
   3023   Location second = locations->InAt(1);
   3024 
   3025   Primitive::Type type = rem->GetResultType();
   3026   switch (type) {
   3027     case Primitive::kPrimInt: {
   3028         if (second.IsConstant()) {
   3029           GenerateDivRemConstantIntegral(rem);
   3030         } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
   3031         Register reg1 = first.AsRegister<Register>();
   3032         Register reg2 = second.AsRegister<Register>();
   3033         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3034 
   3035         // temp = reg1 / reg2  (integer division)
   3036         // dest = reg1 - temp * reg2
   3037         __ sdiv(temp, reg1, reg2);
   3038         __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
   3039       } else {
   3040         InvokeRuntimeCallingConvention calling_convention;
   3041         DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
   3042         DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
   3043         DCHECK_EQ(R1, out.AsRegister<Register>());
   3044 
   3045         codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
   3046         CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
   3047       }
   3048       break;
   3049     }
   3050 
   3051     case Primitive::kPrimLong: {
   3052       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
   3053         CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
   3054       break;
   3055     }
   3056 
   3057     case Primitive::kPrimFloat: {
   3058       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
   3059       CheckEntrypointTypes<kQuickFmodf, float, float, float>();
   3060       break;
   3061     }
   3062 
   3063     case Primitive::kPrimDouble: {
   3064       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
   3065       CheckEntrypointTypes<kQuickFmod, double, double, double>();
   3066       break;
   3067     }
   3068 
   3069     default:
   3070       LOG(FATAL) << "Unexpected rem type " << type;
   3071   }
   3072 }
   3073 
   3074 void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
   3075   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   3076       ? LocationSummary::kCallOnSlowPath
   3077       : LocationSummary::kNoCall;
   3078   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   3079   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
   3080   if (instruction->HasUses()) {
   3081     locations->SetOut(Location::SameAsFirstInput());
   3082   }
   3083 }
   3084 
   3085 void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
   3086   SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
   3087   codegen_->AddSlowPath(slow_path);
   3088 
   3089   LocationSummary* locations = instruction->GetLocations();
   3090   Location value = locations->InAt(0);
   3091 
   3092   switch (instruction->GetType()) {
   3093     case Primitive::kPrimBoolean:
   3094     case Primitive::kPrimByte:
   3095     case Primitive::kPrimChar:
   3096     case Primitive::kPrimShort:
   3097     case Primitive::kPrimInt: {
   3098       if (value.IsRegister()) {
   3099         __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
   3100       } else {
   3101         DCHECK(value.IsConstant()) << value;
   3102         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
   3103           __ b(slow_path->GetEntryLabel());
   3104         }
   3105       }
   3106       break;
   3107     }
   3108     case Primitive::kPrimLong: {
   3109       if (value.IsRegisterPair()) {
   3110         __ orrs(IP,
   3111                 value.AsRegisterPairLow<Register>(),
   3112                 ShifterOperand(value.AsRegisterPairHigh<Register>()));
   3113         __ b(slow_path->GetEntryLabel(), EQ);
   3114       } else {
   3115         DCHECK(value.IsConstant()) << value;
   3116         if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
   3117           __ b(slow_path->GetEntryLabel());
   3118         }
   3119       }
   3120       break;
   3121     default:
   3122       LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
   3123     }
   3124   }
   3125 }
   3126 
   3127 void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
   3128   Register in = locations->InAt(0).AsRegister<Register>();
   3129   Location rhs = locations->InAt(1);
   3130   Register out = locations->Out().AsRegister<Register>();
   3131 
   3132   if (rhs.IsConstant()) {
   3133     // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
   3134     // so map all rotations to a +ve. equivalent in that range.
   3135     // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
   3136     uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
   3137     if (rot) {
   3138       // Rotate, mapping left rotations to right equivalents if necessary.
   3139       // (e.g. left by 2 bits == right by 30.)
   3140       __ Ror(out, in, rot);
   3141     } else if (out != in) {
   3142       __ Mov(out, in);
   3143     }
   3144   } else {
   3145     __ Ror(out, in, rhs.AsRegister<Register>());
   3146   }
   3147 }
   3148 
   3149 // Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
   3150 // rotates by swapping input regs (effectively rotating by the first 32-bits of
   3151 // a larger rotation) or flipping direction (thus treating larger right/left
   3152 // rotations as sub-word sized rotations in the other direction) as appropriate.
   3153 void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
   3154   Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   3155   Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   3156   Location rhs = locations->InAt(1);
   3157   Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
   3158   Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
   3159 
   3160   if (rhs.IsConstant()) {
   3161     uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
   3162     // Map all rotations to +ve. equivalents on the interval [0,63].
   3163     rot &= kMaxLongShiftDistance;
   3164     // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
   3165     // logic below to a simple pair of binary orr.
   3166     // (e.g. 34 bits == in_reg swap + 2 bits right.)
   3167     if (rot >= kArmBitsPerWord) {
   3168       rot -= kArmBitsPerWord;
   3169       std::swap(in_reg_hi, in_reg_lo);
   3170     }
   3171     // Rotate, or mov to out for zero or word size rotations.
   3172     if (rot != 0u) {
   3173       __ Lsr(out_reg_hi, in_reg_hi, rot);
   3174       __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
   3175       __ Lsr(out_reg_lo, in_reg_lo, rot);
   3176       __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
   3177     } else {
   3178       __ Mov(out_reg_lo, in_reg_lo);
   3179       __ Mov(out_reg_hi, in_reg_hi);
   3180     }
   3181   } else {
   3182     Register shift_right = locations->GetTemp(0).AsRegister<Register>();
   3183     Register shift_left = locations->GetTemp(1).AsRegister<Register>();
   3184     Label end;
   3185     Label shift_by_32_plus_shift_right;
   3186 
   3187     __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
   3188     __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
   3189     __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
   3190     __ b(&shift_by_32_plus_shift_right, CC);
   3191 
   3192     // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
   3193     // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
   3194     __ Lsl(out_reg_hi, in_reg_hi, shift_left);
   3195     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
   3196     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
   3197     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
   3198     __ Lsr(shift_left, in_reg_hi, shift_right);
   3199     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
   3200     __ b(&end);
   3201 
   3202     __ Bind(&shift_by_32_plus_shift_right);  // Shift by 32+shift_right.
   3203     // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
   3204     // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
   3205     __ Lsr(out_reg_hi, in_reg_hi, shift_right);
   3206     __ Lsl(out_reg_lo, in_reg_lo, shift_left);
   3207     __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
   3208     __ Lsr(out_reg_lo, in_reg_lo, shift_right);
   3209     __ Lsl(shift_right, in_reg_hi, shift_left);
   3210     __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
   3211 
   3212     __ Bind(&end);
   3213   }
   3214 }
   3215 
   3216 void LocationsBuilderARM::VisitRor(HRor* ror) {
   3217   LocationSummary* locations =
   3218       new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
   3219   switch (ror->GetResultType()) {
   3220     case Primitive::kPrimInt: {
   3221       locations->SetInAt(0, Location::RequiresRegister());
   3222       locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
   3223       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3224       break;
   3225     }
   3226     case Primitive::kPrimLong: {
   3227       locations->SetInAt(0, Location::RequiresRegister());
   3228       if (ror->InputAt(1)->IsConstant()) {
   3229         locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
   3230       } else {
   3231         locations->SetInAt(1, Location::RequiresRegister());
   3232         locations->AddTemp(Location::RequiresRegister());
   3233         locations->AddTemp(Location::RequiresRegister());
   3234       }
   3235       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3236       break;
   3237     }
   3238     default:
   3239       LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
   3240   }
   3241 }
   3242 
   3243 void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
   3244   LocationSummary* locations = ror->GetLocations();
   3245   Primitive::Type type = ror->GetResultType();
   3246   switch (type) {
   3247     case Primitive::kPrimInt: {
   3248       HandleIntegerRotate(locations);
   3249       break;
   3250     }
   3251     case Primitive::kPrimLong: {
   3252       HandleLongRotate(locations);
   3253       break;
   3254     }
   3255     default:
   3256       LOG(FATAL) << "Unexpected operation type " << type;
   3257       UNREACHABLE();
   3258   }
   3259 }
   3260 
   3261 void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
   3262   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
   3263 
   3264   LocationSummary* locations =
   3265       new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
   3266 
   3267   switch (op->GetResultType()) {
   3268     case Primitive::kPrimInt: {
   3269       locations->SetInAt(0, Location::RequiresRegister());
   3270       if (op->InputAt(1)->IsConstant()) {
   3271         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
   3272         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3273       } else {
   3274         locations->SetInAt(1, Location::RequiresRegister());
   3275         // Make the output overlap, as it will be used to hold the masked
   3276         // second input.
   3277         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3278       }
   3279       break;
   3280     }
   3281     case Primitive::kPrimLong: {
   3282       locations->SetInAt(0, Location::RequiresRegister());
   3283       if (op->InputAt(1)->IsConstant()) {
   3284         locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
   3285         // For simplicity, use kOutputOverlap even though we only require that low registers
   3286         // don't clash with high registers which the register allocator currently guarantees.
   3287         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3288       } else {
   3289         locations->SetInAt(1, Location::RequiresRegister());
   3290         locations->AddTemp(Location::RequiresRegister());
   3291         locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3292       }
   3293       break;
   3294     }
   3295     default:
   3296       LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
   3297   }
   3298 }
   3299 
   3300 void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
   3301   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
   3302 
   3303   LocationSummary* locations = op->GetLocations();
   3304   Location out = locations->Out();
   3305   Location first = locations->InAt(0);
   3306   Location second = locations->InAt(1);
   3307 
   3308   Primitive::Type type = op->GetResultType();
   3309   switch (type) {
   3310     case Primitive::kPrimInt: {
   3311       Register out_reg = out.AsRegister<Register>();
   3312       Register first_reg = first.AsRegister<Register>();
   3313       if (second.IsRegister()) {
   3314         Register second_reg = second.AsRegister<Register>();
   3315         // ARM doesn't mask the shift count so we need to do it ourselves.
   3316         __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
   3317         if (op->IsShl()) {
   3318           __ Lsl(out_reg, first_reg, out_reg);
   3319         } else if (op->IsShr()) {
   3320           __ Asr(out_reg, first_reg, out_reg);
   3321         } else {
   3322           __ Lsr(out_reg, first_reg, out_reg);
   3323         }
   3324       } else {
   3325         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
   3326         uint32_t shift_value = cst & kMaxIntShiftDistance;
   3327         if (shift_value == 0) {  // ARM does not support shifting with 0 immediate.
   3328           __ Mov(out_reg, first_reg);
   3329         } else if (op->IsShl()) {
   3330           __ Lsl(out_reg, first_reg, shift_value);
   3331         } else if (op->IsShr()) {
   3332           __ Asr(out_reg, first_reg, shift_value);
   3333         } else {
   3334           __ Lsr(out_reg, first_reg, shift_value);
   3335         }
   3336       }
   3337       break;
   3338     }
   3339     case Primitive::kPrimLong: {
   3340       Register o_h = out.AsRegisterPairHigh<Register>();
   3341       Register o_l = out.AsRegisterPairLow<Register>();
   3342 
   3343       Register high = first.AsRegisterPairHigh<Register>();
   3344       Register low = first.AsRegisterPairLow<Register>();
   3345 
   3346       if (second.IsRegister()) {
   3347         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3348 
   3349         Register second_reg = second.AsRegister<Register>();
   3350 
   3351         if (op->IsShl()) {
   3352           __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3353           // Shift the high part
   3354           __ Lsl(o_h, high, o_l);
   3355           // Shift the low part and `or` what overflew on the high part
   3356           __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
   3357           __ Lsr(temp, low, temp);
   3358           __ orr(o_h, o_h, ShifterOperand(temp));
   3359           // If the shift is > 32 bits, override the high part
   3360           __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
   3361           __ it(PL);
   3362           __ Lsl(o_h, low, temp, PL);
   3363           // Shift the low part
   3364           __ Lsl(o_l, low, o_l);
   3365         } else if (op->IsShr()) {
   3366           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3367           // Shift the low part
   3368           __ Lsr(o_l, low, o_h);
   3369           // Shift the high part and `or` what underflew on the low part
   3370           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3371           __ Lsl(temp, high, temp);
   3372           __ orr(o_l, o_l, ShifterOperand(temp));
   3373           // If the shift is > 32 bits, override the low part
   3374           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3375           __ it(PL);
   3376           __ Asr(o_l, high, temp, PL);
   3377           // Shift the high part
   3378           __ Asr(o_h, high, o_h);
   3379         } else {
   3380           __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
   3381           // same as Shr except we use `Lsr`s and not `Asr`s
   3382           __ Lsr(o_l, low, o_h);
   3383           __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3384           __ Lsl(temp, high, temp);
   3385           __ orr(o_l, o_l, ShifterOperand(temp));
   3386           __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
   3387           __ it(PL);
   3388           __ Lsr(o_l, high, temp, PL);
   3389           __ Lsr(o_h, high, o_h);
   3390         }
   3391       } else {
   3392         // Register allocator doesn't create partial overlap.
   3393         DCHECK_NE(o_l, high);
   3394         DCHECK_NE(o_h, low);
   3395         int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
   3396         uint32_t shift_value = cst & kMaxLongShiftDistance;
   3397         if (shift_value > 32) {
   3398           if (op->IsShl()) {
   3399             __ Lsl(o_h, low, shift_value - 32);
   3400             __ LoadImmediate(o_l, 0);
   3401           } else if (op->IsShr()) {
   3402             __ Asr(o_l, high, shift_value - 32);
   3403             __ Asr(o_h, high, 31);
   3404           } else {
   3405             __ Lsr(o_l, high, shift_value - 32);
   3406             __ LoadImmediate(o_h, 0);
   3407           }
   3408         } else if (shift_value == 32) {
   3409           if (op->IsShl()) {
   3410             __ mov(o_h, ShifterOperand(low));
   3411             __ LoadImmediate(o_l, 0);
   3412           } else if (op->IsShr()) {
   3413             __ mov(o_l, ShifterOperand(high));
   3414             __ Asr(o_h, high, 31);
   3415           } else {
   3416             __ mov(o_l, ShifterOperand(high));
   3417             __ LoadImmediate(o_h, 0);
   3418           }
   3419         } else if (shift_value == 1) {
   3420           if (op->IsShl()) {
   3421             __ Lsls(o_l, low, 1);
   3422             __ adc(o_h, high, ShifterOperand(high));
   3423           } else if (op->IsShr()) {
   3424             __ Asrs(o_h, high, 1);
   3425             __ Rrx(o_l, low);
   3426           } else {
   3427             __ Lsrs(o_h, high, 1);
   3428             __ Rrx(o_l, low);
   3429           }
   3430         } else {
   3431           DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
   3432           if (op->IsShl()) {
   3433             __ Lsl(o_h, high, shift_value);
   3434             __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
   3435             __ Lsl(o_l, low, shift_value);
   3436           } else if (op->IsShr()) {
   3437             __ Lsr(o_l, low, shift_value);
   3438             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
   3439             __ Asr(o_h, high, shift_value);
   3440           } else {
   3441             __ Lsr(o_l, low, shift_value);
   3442             __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
   3443             __ Lsr(o_h, high, shift_value);
   3444           }
   3445         }
   3446       }
   3447       break;
   3448     }
   3449     default:
   3450       LOG(FATAL) << "Unexpected operation type " << type;
   3451       UNREACHABLE();
   3452   }
   3453 }
   3454 
   3455 void LocationsBuilderARM::VisitShl(HShl* shl) {
   3456   HandleShift(shl);
   3457 }
   3458 
   3459 void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
   3460   HandleShift(shl);
   3461 }
   3462 
   3463 void LocationsBuilderARM::VisitShr(HShr* shr) {
   3464   HandleShift(shr);
   3465 }
   3466 
   3467 void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
   3468   HandleShift(shr);
   3469 }
   3470 
   3471 void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
   3472   HandleShift(ushr);
   3473 }
   3474 
   3475 void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
   3476   HandleShift(ushr);
   3477 }
   3478 
   3479 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
   3480   LocationSummary* locations =
   3481       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   3482   if (instruction->IsStringAlloc()) {
   3483     locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
   3484   } else {
   3485     InvokeRuntimeCallingConvention calling_convention;
   3486     locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   3487     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   3488   }
   3489   locations->SetOut(Location::RegisterLocation(R0));
   3490 }
   3491 
   3492 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
   3493   // Note: if heap poisoning is enabled, the entry point takes cares
   3494   // of poisoning the reference.
   3495   if (instruction->IsStringAlloc()) {
   3496     // String is allocated through StringFactory. Call NewEmptyString entry point.
   3497     Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
   3498     MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
   3499     __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
   3500     __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
   3501     __ blx(LR);
   3502     codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
   3503   } else {
   3504     codegen_->InvokeRuntime(instruction->GetEntrypoint(),
   3505                             instruction,
   3506                             instruction->GetDexPc(),
   3507                             nullptr);
   3508     CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
   3509   }
   3510 }
   3511 
   3512 void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
   3513   LocationSummary* locations =
   3514       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   3515   InvokeRuntimeCallingConvention calling_convention;
   3516   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   3517   locations->SetOut(Location::RegisterLocation(R0));
   3518   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   3519   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   3520 }
   3521 
   3522 void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
   3523   InvokeRuntimeCallingConvention calling_convention;
   3524   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
   3525   // Note: if heap poisoning is enabled, the entry point takes cares
   3526   // of poisoning the reference.
   3527   codegen_->InvokeRuntime(instruction->GetEntrypoint(),
   3528                           instruction,
   3529                           instruction->GetDexPc(),
   3530                           nullptr);
   3531   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
   3532 }
   3533 
   3534 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
   3535   LocationSummary* locations =
   3536       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3537   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
   3538   if (location.IsStackSlot()) {
   3539     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
   3540   } else if (location.IsDoubleStackSlot()) {
   3541     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
   3542   }
   3543   locations->SetOut(location);
   3544 }
   3545 
   3546 void InstructionCodeGeneratorARM::VisitParameterValue(
   3547     HParameterValue* instruction ATTRIBUTE_UNUSED) {
   3548   // Nothing to do, the parameter is already at its location.
   3549 }
   3550 
   3551 void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
   3552   LocationSummary* locations =
   3553       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3554   locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
   3555 }
   3556 
   3557 void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
   3558   // Nothing to do, the method is already at its location.
   3559 }
   3560 
   3561 void LocationsBuilderARM::VisitNot(HNot* not_) {
   3562   LocationSummary* locations =
   3563       new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   3564   locations->SetInAt(0, Location::RequiresRegister());
   3565   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3566 }
   3567 
   3568 void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
   3569   LocationSummary* locations = not_->GetLocations();
   3570   Location out = locations->Out();
   3571   Location in = locations->InAt(0);
   3572   switch (not_->GetResultType()) {
   3573     case Primitive::kPrimInt:
   3574       __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
   3575       break;
   3576 
   3577     case Primitive::kPrimLong:
   3578       __ mvn(out.AsRegisterPairLow<Register>(),
   3579              ShifterOperand(in.AsRegisterPairLow<Register>()));
   3580       __ mvn(out.AsRegisterPairHigh<Register>(),
   3581              ShifterOperand(in.AsRegisterPairHigh<Register>()));
   3582       break;
   3583 
   3584     default:
   3585       LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
   3586   }
   3587 }
   3588 
   3589 void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
   3590   LocationSummary* locations =
   3591       new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
   3592   locations->SetInAt(0, Location::RequiresRegister());
   3593   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   3594 }
   3595 
   3596 void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
   3597   LocationSummary* locations = bool_not->GetLocations();
   3598   Location out = locations->Out();
   3599   Location in = locations->InAt(0);
   3600   __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
   3601 }
   3602 
   3603 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
   3604   LocationSummary* locations =
   3605       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   3606   switch (compare->InputAt(0)->GetType()) {
   3607     case Primitive::kPrimBoolean:
   3608     case Primitive::kPrimByte:
   3609     case Primitive::kPrimShort:
   3610     case Primitive::kPrimChar:
   3611     case Primitive::kPrimInt:
   3612     case Primitive::kPrimLong: {
   3613       locations->SetInAt(0, Location::RequiresRegister());
   3614       locations->SetInAt(1, Location::RequiresRegister());
   3615       // Output overlaps because it is written before doing the low comparison.
   3616       locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   3617       break;
   3618     }
   3619     case Primitive::kPrimFloat:
   3620     case Primitive::kPrimDouble: {
   3621       locations->SetInAt(0, Location::RequiresFpuRegister());
   3622       locations->SetInAt(1, Location::RequiresFpuRegister());
   3623       locations->SetOut(Location::RequiresRegister());
   3624       break;
   3625     }
   3626     default:
   3627       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
   3628   }
   3629 }
   3630 
   3631 void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
   3632   LocationSummary* locations = compare->GetLocations();
   3633   Register out = locations->Out().AsRegister<Register>();
   3634   Location left = locations->InAt(0);
   3635   Location right = locations->InAt(1);
   3636 
   3637   Label less, greater, done;
   3638   Primitive::Type type = compare->InputAt(0)->GetType();
   3639   Condition less_cond;
   3640   switch (type) {
   3641     case Primitive::kPrimBoolean:
   3642     case Primitive::kPrimByte:
   3643     case Primitive::kPrimShort:
   3644     case Primitive::kPrimChar:
   3645     case Primitive::kPrimInt: {
   3646       __ LoadImmediate(out, 0);
   3647       __ cmp(left.AsRegister<Register>(),
   3648              ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
   3649       less_cond = LT;
   3650       break;
   3651     }
   3652     case Primitive::kPrimLong: {
   3653       __ cmp(left.AsRegisterPairHigh<Register>(),
   3654              ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
   3655       __ b(&less, LT);
   3656       __ b(&greater, GT);
   3657       // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
   3658       __ LoadImmediate(out, 0);
   3659       __ cmp(left.AsRegisterPairLow<Register>(),
   3660              ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
   3661       less_cond = LO;
   3662       break;
   3663     }
   3664     case Primitive::kPrimFloat:
   3665     case Primitive::kPrimDouble: {
   3666       __ LoadImmediate(out, 0);
   3667       if (type == Primitive::kPrimFloat) {
   3668         __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
   3669       } else {
   3670         __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
   3671                  FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
   3672       }
   3673       __ vmstat();  // transfer FP status register to ARM APSR.
   3674       less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
   3675       break;
   3676     }
   3677     default:
   3678       LOG(FATAL) << "Unexpected compare type " << type;
   3679       UNREACHABLE();
   3680   }
   3681 
   3682   __ b(&done, EQ);
   3683   __ b(&less, less_cond);
   3684 
   3685   __ Bind(&greater);
   3686   __ LoadImmediate(out, 1);
   3687   __ b(&done);
   3688 
   3689   __ Bind(&less);
   3690   __ LoadImmediate(out, -1);
   3691 
   3692   __ Bind(&done);
   3693 }
   3694 
   3695 void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
   3696   LocationSummary* locations =
   3697       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3698   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
   3699     locations->SetInAt(i, Location::Any());
   3700   }
   3701   locations->SetOut(Location::Any());
   3702 }
   3703 
   3704 void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
   3705   LOG(FATAL) << "Unreachable";
   3706 }
   3707 
   3708 void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
   3709   // TODO (ported from quick): revisit ARM barrier kinds.
   3710   DmbOptions flavor = DmbOptions::ISH;  // Quiet C++ warnings.
   3711   switch (kind) {
   3712     case MemBarrierKind::kAnyStore:
   3713     case MemBarrierKind::kLoadAny:
   3714     case MemBarrierKind::kAnyAny: {
   3715       flavor = DmbOptions::ISH;
   3716       break;
   3717     }
   3718     case MemBarrierKind::kStoreStore: {
   3719       flavor = DmbOptions::ISHST;
   3720       break;
   3721     }
   3722     default:
   3723       LOG(FATAL) << "Unexpected memory barrier " << kind;
   3724   }
   3725   __ dmb(flavor);
   3726 }
   3727 
   3728 void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
   3729                                                          uint32_t offset,
   3730                                                          Register out_lo,
   3731                                                          Register out_hi) {
   3732   if (offset != 0) {
   3733     // Ensure `out_lo` is different from `addr`, so that loading
   3734     // `offset` into `out_lo` does not clutter `addr`.
   3735     DCHECK_NE(out_lo, addr);
   3736     __ LoadImmediate(out_lo, offset);
   3737     __ add(IP, addr, ShifterOperand(out_lo));
   3738     addr = IP;
   3739   }
   3740   __ ldrexd(out_lo, out_hi, addr);
   3741 }
   3742 
   3743 void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
   3744                                                           uint32_t offset,
   3745                                                           Register value_lo,
   3746                                                           Register value_hi,
   3747                                                           Register temp1,
   3748                                                           Register temp2,
   3749                                                           HInstruction* instruction) {
   3750   Label fail;
   3751   if (offset != 0) {
   3752     __ LoadImmediate(temp1, offset);
   3753     __ add(IP, addr, ShifterOperand(temp1));
   3754     addr = IP;
   3755   }
   3756   __ Bind(&fail);
   3757   // We need a load followed by store. (The address used in a STREX instruction must
   3758   // be the same as the address in the most recently executed LDREX instruction.)
   3759   __ ldrexd(temp1, temp2, addr);
   3760   codegen_->MaybeRecordImplicitNullCheck(instruction);
   3761   __ strexd(temp1, value_lo, value_hi, addr);
   3762   __ CompareAndBranchIfNonZero(temp1, &fail);
   3763 }
   3764 
   3765 void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
   3766   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   3767 
   3768   LocationSummary* locations =
   3769       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   3770   locations->SetInAt(0, Location::RequiresRegister());
   3771 
   3772   Primitive::Type field_type = field_info.GetFieldType();
   3773   if (Primitive::IsFloatingPointType(field_type)) {
   3774     locations->SetInAt(1, Location::RequiresFpuRegister());
   3775   } else {
   3776     locations->SetInAt(1, Location::RequiresRegister());
   3777   }
   3778 
   3779   bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
   3780   bool generate_volatile = field_info.IsVolatile()
   3781       && is_wide
   3782       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3783   bool needs_write_barrier =
   3784       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   3785   // Temporary registers for the write barrier.
   3786   // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
   3787   if (needs_write_barrier) {
   3788     locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
   3789     locations->AddTemp(Location::RequiresRegister());
   3790   } else if (generate_volatile) {
   3791     // ARM encoding have some additional constraints for ldrexd/strexd:
   3792     // - registers need to be consecutive
   3793     // - the first register should be even but not R14.
   3794     // We don't test for ARM yet, and the assertion makes sure that we
   3795     // revisit this if we ever enable ARM encoding.
   3796     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
   3797 
   3798     locations->AddTemp(Location::RequiresRegister());
   3799     locations->AddTemp(Location::RequiresRegister());
   3800     if (field_type == Primitive::kPrimDouble) {
   3801       // For doubles we need two more registers to copy the value.
   3802       locations->AddTemp(Location::RegisterLocation(R2));
   3803       locations->AddTemp(Location::RegisterLocation(R3));
   3804     }
   3805   }
   3806 }
   3807 
   3808 void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
   3809                                                  const FieldInfo& field_info,
   3810                                                  bool value_can_be_null) {
   3811   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   3812 
   3813   LocationSummary* locations = instruction->GetLocations();
   3814   Register base = locations->InAt(0).AsRegister<Register>();
   3815   Location value = locations->InAt(1);
   3816 
   3817   bool is_volatile = field_info.IsVolatile();
   3818   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3819   Primitive::Type field_type = field_info.GetFieldType();
   3820   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   3821   bool needs_write_barrier =
   3822       CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   3823 
   3824   if (is_volatile) {
   3825     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
   3826   }
   3827 
   3828   switch (field_type) {
   3829     case Primitive::kPrimBoolean:
   3830     case Primitive::kPrimByte: {
   3831       __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
   3832       break;
   3833     }
   3834 
   3835     case Primitive::kPrimShort:
   3836     case Primitive::kPrimChar: {
   3837       __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
   3838       break;
   3839     }
   3840 
   3841     case Primitive::kPrimInt:
   3842     case Primitive::kPrimNot: {
   3843       if (kPoisonHeapReferences && needs_write_barrier) {
   3844         // Note that in the case where `value` is a null reference,
   3845         // we do not enter this block, as a null reference does not
   3846         // need poisoning.
   3847         DCHECK_EQ(field_type, Primitive::kPrimNot);
   3848         Register temp = locations->GetTemp(0).AsRegister<Register>();
   3849         __ Mov(temp, value.AsRegister<Register>());
   3850         __ PoisonHeapReference(temp);
   3851         __ StoreToOffset(kStoreWord, temp, base, offset);
   3852       } else {
   3853         __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
   3854       }
   3855       break;
   3856     }
   3857 
   3858     case Primitive::kPrimLong: {
   3859       if (is_volatile && !atomic_ldrd_strd) {
   3860         GenerateWideAtomicStore(base, offset,
   3861                                 value.AsRegisterPairLow<Register>(),
   3862                                 value.AsRegisterPairHigh<Register>(),
   3863                                 locations->GetTemp(0).AsRegister<Register>(),
   3864                                 locations->GetTemp(1).AsRegister<Register>(),
   3865                                 instruction);
   3866       } else {
   3867         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
   3868         codegen_->MaybeRecordImplicitNullCheck(instruction);
   3869       }
   3870       break;
   3871     }
   3872 
   3873     case Primitive::kPrimFloat: {
   3874       __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
   3875       break;
   3876     }
   3877 
   3878     case Primitive::kPrimDouble: {
   3879       DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
   3880       if (is_volatile && !atomic_ldrd_strd) {
   3881         Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
   3882         Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
   3883 
   3884         __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
   3885 
   3886         GenerateWideAtomicStore(base, offset,
   3887                                 value_reg_lo,
   3888                                 value_reg_hi,
   3889                                 locations->GetTemp(2).AsRegister<Register>(),
   3890                                 locations->GetTemp(3).AsRegister<Register>(),
   3891                                 instruction);
   3892       } else {
   3893         __ StoreDToOffset(value_reg, base, offset);
   3894         codegen_->MaybeRecordImplicitNullCheck(instruction);
   3895       }
   3896       break;
   3897     }
   3898 
   3899     case Primitive::kPrimVoid:
   3900       LOG(FATAL) << "Unreachable type " << field_type;
   3901       UNREACHABLE();
   3902   }
   3903 
   3904   // Longs and doubles are handled in the switch.
   3905   if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
   3906     codegen_->MaybeRecordImplicitNullCheck(instruction);
   3907   }
   3908 
   3909   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
   3910     Register temp = locations->GetTemp(0).AsRegister<Register>();
   3911     Register card = locations->GetTemp(1).AsRegister<Register>();
   3912     codegen_->MarkGCCard(
   3913         temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   3914   }
   3915 
   3916   if (is_volatile) {
   3917     codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
   3918   }
   3919 }
   3920 
   3921 void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
   3922   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   3923 
   3924   bool object_field_get_with_read_barrier =
   3925       kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
   3926   LocationSummary* locations =
   3927       new (GetGraph()->GetArena()) LocationSummary(instruction,
   3928                                                    object_field_get_with_read_barrier ?
   3929                                                        LocationSummary::kCallOnSlowPath :
   3930                                                        LocationSummary::kNoCall);
   3931   locations->SetInAt(0, Location::RequiresRegister());
   3932 
   3933   bool volatile_for_double = field_info.IsVolatile()
   3934       && (field_info.GetFieldType() == Primitive::kPrimDouble)
   3935       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   3936   // The output overlaps in case of volatile long: we don't want the
   3937   // code generated by GenerateWideAtomicLoad to overwrite the
   3938   // object's location.  Likewise, in the case of an object field get
   3939   // with read barriers enabled, we do not want the load to overwrite
   3940   // the object's location, as we need it to emit the read barrier.
   3941   bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
   3942       object_field_get_with_read_barrier;
   3943 
   3944   if (Primitive::IsFloatingPointType(instruction->GetType())) {
   3945     locations->SetOut(Location::RequiresFpuRegister());
   3946   } else {
   3947     locations->SetOut(Location::RequiresRegister(),
   3948                       (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
   3949   }
   3950   if (volatile_for_double) {
   3951     // ARM encoding have some additional constraints for ldrexd/strexd:
   3952     // - registers need to be consecutive
   3953     // - the first register should be even but not R14.
   3954     // We don't test for ARM yet, and the assertion makes sure that we
   3955     // revisit this if we ever enable ARM encoding.
   3956     DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
   3957     locations->AddTemp(Location::RequiresRegister());
   3958     locations->AddTemp(Location::RequiresRegister());
   3959   } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
   3960     // We need a temporary register for the read barrier marking slow
   3961     // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
   3962     locations->AddTemp(Location::RequiresRegister());
   3963   }
   3964 }
   3965 
   3966 Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
   3967                                                              Opcode opcode) {
   3968   DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
   3969   if (constant->IsConstant() &&
   3970       CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
   3971     return Location::ConstantLocation(constant->AsConstant());
   3972   }
   3973   return Location::RequiresRegister();
   3974 }
   3975 
   3976 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
   3977                                                        Opcode opcode) {
   3978   uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
   3979   if (Primitive::Is64BitType(input_cst->GetType())) {
   3980     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
   3981         CanEncodeConstantAsImmediate(High32Bits(value), opcode);
   3982   } else {
   3983     return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
   3984   }
   3985 }
   3986 
   3987 bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
   3988   ShifterOperand so;
   3989   ArmAssembler* assembler = codegen_->GetAssembler();
   3990   if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
   3991     return true;
   3992   }
   3993   Opcode neg_opcode = kNoOperand;
   3994   switch (opcode) {
   3995     case AND:
   3996       neg_opcode = BIC;
   3997       break;
   3998     case ORR:
   3999       neg_opcode = ORN;
   4000       break;
   4001     default:
   4002       return false;
   4003   }
   4004   return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
   4005 }
   4006 
   4007 void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
   4008                                                  const FieldInfo& field_info) {
   4009   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   4010 
   4011   LocationSummary* locations = instruction->GetLocations();
   4012   Location base_loc = locations->InAt(0);
   4013   Register base = base_loc.AsRegister<Register>();
   4014   Location out = locations->Out();
   4015   bool is_volatile = field_info.IsVolatile();
   4016   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   4017   Primitive::Type field_type = field_info.GetFieldType();
   4018   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
   4019 
   4020   switch (field_type) {
   4021     case Primitive::kPrimBoolean:
   4022       __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
   4023       break;
   4024 
   4025     case Primitive::kPrimByte:
   4026       __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
   4027       break;
   4028 
   4029     case Primitive::kPrimShort:
   4030       __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
   4031       break;
   4032 
   4033     case Primitive::kPrimChar:
   4034       __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
   4035       break;
   4036 
   4037     case Primitive::kPrimInt:
   4038       __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
   4039       break;
   4040 
   4041     case Primitive::kPrimNot: {
   4042       // /* HeapReference<Object> */ out = *(base + offset)
   4043       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   4044         Location temp_loc = locations->GetTemp(0);
   4045         // Note that a potential implicit null check is handled in this
   4046         // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
   4047         codegen_->GenerateFieldLoadWithBakerReadBarrier(
   4048             instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
   4049         if (is_volatile) {
   4050           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4051         }
   4052       } else {
   4053         __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
   4054         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4055         if (is_volatile) {
   4056           codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4057         }
   4058         // If read barriers are enabled, emit read barriers other than
   4059         // Baker's using a slow path (and also unpoison the loaded
   4060         // reference, if heap poisoning is enabled).
   4061         codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
   4062       }
   4063       break;
   4064     }
   4065 
   4066     case Primitive::kPrimLong:
   4067       if (is_volatile && !atomic_ldrd_strd) {
   4068         GenerateWideAtomicLoad(base, offset,
   4069                                out.AsRegisterPairLow<Register>(),
   4070                                out.AsRegisterPairHigh<Register>());
   4071       } else {
   4072         __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
   4073       }
   4074       break;
   4075 
   4076     case Primitive::kPrimFloat:
   4077       __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
   4078       break;
   4079 
   4080     case Primitive::kPrimDouble: {
   4081       DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
   4082       if (is_volatile && !atomic_ldrd_strd) {
   4083         Register lo = locations->GetTemp(0).AsRegister<Register>();
   4084         Register hi = locations->GetTemp(1).AsRegister<Register>();
   4085         GenerateWideAtomicLoad(base, offset, lo, hi);
   4086         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4087         __ vmovdrr(out_reg, lo, hi);
   4088       } else {
   4089         __ LoadDFromOffset(out_reg, base, offset);
   4090         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4091       }
   4092       break;
   4093     }
   4094 
   4095     case Primitive::kPrimVoid:
   4096       LOG(FATAL) << "Unreachable type " << field_type;
   4097       UNREACHABLE();
   4098   }
   4099 
   4100   if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
   4101     // Potential implicit null checks, in the case of reference or
   4102     // double fields, are handled in the previous switch statement.
   4103   } else {
   4104     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4105   }
   4106 
   4107   if (is_volatile) {
   4108     if (field_type == Primitive::kPrimNot) {
   4109       // Memory barriers, in the case of references, are also handled
   4110       // in the previous switch statement.
   4111     } else {
   4112       codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   4113     }
   4114   }
   4115 }
   4116 
   4117 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   4118   HandleFieldSet(instruction, instruction->GetFieldInfo());
   4119 }
   4120 
   4121 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
   4122   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
   4123 }
   4124 
   4125 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   4126   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4127 }
   4128 
   4129 void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   4130   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4131 }
   4132 
   4133 void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
   4134   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4135 }
   4136 
   4137 void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
   4138   HandleFieldGet(instruction, instruction->GetFieldInfo());
   4139 }
   4140 
   4141 void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   4142   HandleFieldSet(instruction, instruction->GetFieldInfo());
   4143 }
   4144 
   4145 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
   4146   HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
   4147 }
   4148 
   4149 void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
   4150     HUnresolvedInstanceFieldGet* instruction) {
   4151   FieldAccessCallingConventionARM calling_convention;
   4152   codegen_->CreateUnresolvedFieldLocationSummary(
   4153       instruction, instruction->GetFieldType(), calling_convention);
   4154 }
   4155 
   4156 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
   4157     HUnresolvedInstanceFieldGet* instruction) {
   4158   FieldAccessCallingConventionARM calling_convention;
   4159   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4160                                           instruction->GetFieldType(),
   4161                                           instruction->GetFieldIndex(),
   4162                                           instruction->GetDexPc(),
   4163                                           calling_convention);
   4164 }
   4165 
   4166 void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
   4167     HUnresolvedInstanceFieldSet* instruction) {
   4168   FieldAccessCallingConventionARM calling_convention;
   4169   codegen_->CreateUnresolvedFieldLocationSummary(
   4170       instruction, instruction->GetFieldType(), calling_convention);
   4171 }
   4172 
   4173 void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
   4174     HUnresolvedInstanceFieldSet* instruction) {
   4175   FieldAccessCallingConventionARM calling_convention;
   4176   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4177                                           instruction->GetFieldType(),
   4178                                           instruction->GetFieldIndex(),
   4179                                           instruction->GetDexPc(),
   4180                                           calling_convention);
   4181 }
   4182 
   4183 void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
   4184     HUnresolvedStaticFieldGet* instruction) {
   4185   FieldAccessCallingConventionARM calling_convention;
   4186   codegen_->CreateUnresolvedFieldLocationSummary(
   4187       instruction, instruction->GetFieldType(), calling_convention);
   4188 }
   4189 
   4190 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
   4191     HUnresolvedStaticFieldGet* instruction) {
   4192   FieldAccessCallingConventionARM calling_convention;
   4193   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4194                                           instruction->GetFieldType(),
   4195                                           instruction->GetFieldIndex(),
   4196                                           instruction->GetDexPc(),
   4197                                           calling_convention);
   4198 }
   4199 
   4200 void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
   4201     HUnresolvedStaticFieldSet* instruction) {
   4202   FieldAccessCallingConventionARM calling_convention;
   4203   codegen_->CreateUnresolvedFieldLocationSummary(
   4204       instruction, instruction->GetFieldType(), calling_convention);
   4205 }
   4206 
   4207 void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
   4208     HUnresolvedStaticFieldSet* instruction) {
   4209   FieldAccessCallingConventionARM calling_convention;
   4210   codegen_->GenerateUnresolvedFieldAccess(instruction,
   4211                                           instruction->GetFieldType(),
   4212                                           instruction->GetFieldIndex(),
   4213                                           instruction->GetDexPc(),
   4214                                           calling_convention);
   4215 }
   4216 
   4217 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
   4218   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   4219       ? LocationSummary::kCallOnSlowPath
   4220       : LocationSummary::kNoCall;
   4221   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   4222   locations->SetInAt(0, Location::RequiresRegister());
   4223   if (instruction->HasUses()) {
   4224     locations->SetOut(Location::SameAsFirstInput());
   4225   }
   4226 }
   4227 
   4228 void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
   4229   if (CanMoveNullCheckToUser(instruction)) {
   4230     return;
   4231   }
   4232   Location obj = instruction->GetLocations()->InAt(0);
   4233 
   4234   __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
   4235   RecordPcInfo(instruction, instruction->GetDexPc());
   4236 }
   4237 
   4238 void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
   4239   SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
   4240   AddSlowPath(slow_path);
   4241 
   4242   LocationSummary* locations = instruction->GetLocations();
   4243   Location obj = locations->InAt(0);
   4244 
   4245   __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
   4246 }
   4247 
   4248 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
   4249   codegen_->GenerateNullCheck(instruction);
   4250 }
   4251 
   4252 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
   4253   bool object_array_get_with_read_barrier =
   4254       kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
   4255   LocationSummary* locations =
   4256       new (GetGraph()->GetArena()) LocationSummary(instruction,
   4257                                                    object_array_get_with_read_barrier ?
   4258                                                        LocationSummary::kCallOnSlowPath :
   4259                                                        LocationSummary::kNoCall);
   4260   locations->SetInAt(0, Location::RequiresRegister());
   4261   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   4262   if (Primitive::IsFloatingPointType(instruction->GetType())) {
   4263     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
   4264   } else {
   4265     // The output overlaps in the case of an object array get with
   4266     // read barriers enabled: we do not want the move to overwrite the
   4267     // array's location, as we need it to emit the read barrier.
   4268     locations->SetOut(
   4269         Location::RequiresRegister(),
   4270         object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
   4271   }
   4272   // We need a temporary register for the read barrier marking slow
   4273   // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
   4274   if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
   4275     locations->AddTemp(Location::RequiresRegister());
   4276   }
   4277 }
   4278 
   4279 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
   4280   LocationSummary* locations = instruction->GetLocations();
   4281   Location obj_loc = locations->InAt(0);
   4282   Register obj = obj_loc.AsRegister<Register>();
   4283   Location index = locations->InAt(1);
   4284   Location out_loc = locations->Out();
   4285 
   4286   Primitive::Type type = instruction->GetType();
   4287   switch (type) {
   4288     case Primitive::kPrimBoolean: {
   4289       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   4290       Register out = out_loc.AsRegister<Register>();
   4291       if (index.IsConstant()) {
   4292         size_t offset =
   4293             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4294         __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
   4295       } else {
   4296         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
   4297         __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
   4298       }
   4299       break;
   4300     }
   4301 
   4302     case Primitive::kPrimByte: {
   4303       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
   4304       Register out = out_loc.AsRegister<Register>();
   4305       if (index.IsConstant()) {
   4306         size_t offset =
   4307             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4308         __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
   4309       } else {
   4310         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
   4311         __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
   4312       }
   4313       break;
   4314     }
   4315 
   4316     case Primitive::kPrimShort: {
   4317       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
   4318       Register out = out_loc.AsRegister<Register>();
   4319       if (index.IsConstant()) {
   4320         size_t offset =
   4321             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4322         __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
   4323       } else {
   4324         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4325         __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
   4326       }
   4327       break;
   4328     }
   4329 
   4330     case Primitive::kPrimChar: {
   4331       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   4332       Register out = out_loc.AsRegister<Register>();
   4333       if (index.IsConstant()) {
   4334         size_t offset =
   4335             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4336         __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
   4337       } else {
   4338         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4339         __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
   4340       }
   4341       break;
   4342     }
   4343 
   4344     case Primitive::kPrimInt: {
   4345       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4346       Register out = out_loc.AsRegister<Register>();
   4347       if (index.IsConstant()) {
   4348         size_t offset =
   4349             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4350         __ LoadFromOffset(kLoadWord, out, obj, offset);
   4351       } else {
   4352         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4353         __ LoadFromOffset(kLoadWord, out, IP, data_offset);
   4354       }
   4355       break;
   4356     }
   4357 
   4358     case Primitive::kPrimNot: {
   4359       static_assert(
   4360           sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
   4361           "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
   4362       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4363       // /* HeapReference<Object> */ out =
   4364       //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
   4365       if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   4366         Location temp = locations->GetTemp(0);
   4367         // Note that a potential implicit null check is handled in this
   4368         // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
   4369         codegen_->GenerateArrayLoadWithBakerReadBarrier(
   4370             instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
   4371       } else {
   4372         Register out = out_loc.AsRegister<Register>();
   4373         if (index.IsConstant()) {
   4374           size_t offset =
   4375               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4376           __ LoadFromOffset(kLoadWord, out, obj, offset);
   4377           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4378           // If read barriers are enabled, emit read barriers other than
   4379           // Baker's using a slow path (and also unpoison the loaded
   4380           // reference, if heap poisoning is enabled).
   4381           codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
   4382         } else {
   4383           __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4384           __ LoadFromOffset(kLoadWord, out, IP, data_offset);
   4385           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4386           // If read barriers are enabled, emit read barriers other than
   4387           // Baker's using a slow path (and also unpoison the loaded
   4388           // reference, if heap poisoning is enabled).
   4389           codegen_->MaybeGenerateReadBarrierSlow(
   4390               instruction, out_loc, out_loc, obj_loc, data_offset, index);
   4391         }
   4392       }
   4393       break;
   4394     }
   4395 
   4396     case Primitive::kPrimLong: {
   4397       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   4398       if (index.IsConstant()) {
   4399         size_t offset =
   4400             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4401         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
   4402       } else {
   4403         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4404         __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
   4405       }
   4406       break;
   4407     }
   4408 
   4409     case Primitive::kPrimFloat: {
   4410       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
   4411       SRegister out = out_loc.AsFpuRegister<SRegister>();
   4412       if (index.IsConstant()) {
   4413         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4414         __ LoadSFromOffset(out, obj, offset);
   4415       } else {
   4416         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4417         __ LoadSFromOffset(out, IP, data_offset);
   4418       }
   4419       break;
   4420     }
   4421 
   4422     case Primitive::kPrimDouble: {
   4423       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
   4424       SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
   4425       if (index.IsConstant()) {
   4426         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4427         __ LoadDFromOffset(FromLowSToD(out), obj, offset);
   4428       } else {
   4429         __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4430         __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
   4431       }
   4432       break;
   4433     }
   4434 
   4435     case Primitive::kPrimVoid:
   4436       LOG(FATAL) << "Unreachable type " << type;
   4437       UNREACHABLE();
   4438   }
   4439 
   4440   if (type == Primitive::kPrimNot) {
   4441     // Potential implicit null checks, in the case of reference
   4442     // arrays, are handled in the previous switch statement.
   4443   } else {
   4444     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4445   }
   4446 }
   4447 
   4448 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
   4449   Primitive::Type value_type = instruction->GetComponentType();
   4450 
   4451   bool needs_write_barrier =
   4452       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
   4453   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   4454   bool object_array_set_with_read_barrier =
   4455       kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
   4456 
   4457   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
   4458       instruction,
   4459       (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
   4460           LocationSummary::kCallOnSlowPath :
   4461           LocationSummary::kNoCall);
   4462 
   4463   locations->SetInAt(0, Location::RequiresRegister());
   4464   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   4465   if (Primitive::IsFloatingPointType(value_type)) {
   4466     locations->SetInAt(2, Location::RequiresFpuRegister());
   4467   } else {
   4468     locations->SetInAt(2, Location::RequiresRegister());
   4469   }
   4470   if (needs_write_barrier) {
   4471     // Temporary registers for the write barrier.
   4472     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
   4473     locations->AddTemp(Location::RequiresRegister());
   4474   }
   4475 }
   4476 
   4477 void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
   4478   LocationSummary* locations = instruction->GetLocations();
   4479   Location array_loc = locations->InAt(0);
   4480   Register array = array_loc.AsRegister<Register>();
   4481   Location index = locations->InAt(1);
   4482   Primitive::Type value_type = instruction->GetComponentType();
   4483   bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
   4484   bool needs_write_barrier =
   4485       CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
   4486 
   4487   switch (value_type) {
   4488     case Primitive::kPrimBoolean:
   4489     case Primitive::kPrimByte: {
   4490       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
   4491       Register value = locations->InAt(2).AsRegister<Register>();
   4492       if (index.IsConstant()) {
   4493         size_t offset =
   4494             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
   4495         __ StoreToOffset(kStoreByte, value, array, offset);
   4496       } else {
   4497         __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
   4498         __ StoreToOffset(kStoreByte, value, IP, data_offset);
   4499       }
   4500       break;
   4501     }
   4502 
   4503     case Primitive::kPrimShort:
   4504     case Primitive::kPrimChar: {
   4505       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
   4506       Register value = locations->InAt(2).AsRegister<Register>();
   4507       if (index.IsConstant()) {
   4508         size_t offset =
   4509             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
   4510         __ StoreToOffset(kStoreHalfword, value, array, offset);
   4511       } else {
   4512         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
   4513         __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
   4514       }
   4515       break;
   4516     }
   4517 
   4518     case Primitive::kPrimNot: {
   4519       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4520       Location value_loc = locations->InAt(2);
   4521       Register value = value_loc.AsRegister<Register>();
   4522       Register source = value;
   4523 
   4524       if (instruction->InputAt(2)->IsNullConstant()) {
   4525         // Just setting null.
   4526         if (index.IsConstant()) {
   4527           size_t offset =
   4528               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4529           __ StoreToOffset(kStoreWord, source, array, offset);
   4530         } else {
   4531           DCHECK(index.IsRegister()) << index;
   4532           __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4533           __ StoreToOffset(kStoreWord, source, IP, data_offset);
   4534         }
   4535         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4536         DCHECK(!needs_write_barrier);
   4537         DCHECK(!may_need_runtime_call_for_type_check);
   4538         break;
   4539       }
   4540 
   4541       DCHECK(needs_write_barrier);
   4542       Register temp1 = locations->GetTemp(0).AsRegister<Register>();
   4543       Register temp2 = locations->GetTemp(1).AsRegister<Register>();
   4544       uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   4545       uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   4546       uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   4547       Label done;
   4548       SlowPathCode* slow_path = nullptr;
   4549 
   4550       if (may_need_runtime_call_for_type_check) {
   4551         slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
   4552         codegen_->AddSlowPath(slow_path);
   4553         if (instruction->GetValueCanBeNull()) {
   4554           Label non_zero;
   4555           __ CompareAndBranchIfNonZero(value, &non_zero);
   4556           if (index.IsConstant()) {
   4557             size_t offset =
   4558                (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4559             __ StoreToOffset(kStoreWord, value, array, offset);
   4560           } else {
   4561             DCHECK(index.IsRegister()) << index;
   4562             __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4563             __ StoreToOffset(kStoreWord, value, IP, data_offset);
   4564           }
   4565           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4566           __ b(&done);
   4567           __ Bind(&non_zero);
   4568         }
   4569 
   4570         if (kEmitCompilerReadBarrier) {
   4571           // When read barriers are enabled, the type checking
   4572           // instrumentation requires two read barriers:
   4573           //
   4574           //   __ Mov(temp2, temp1);
   4575           //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
   4576           //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
   4577           //   codegen_->GenerateReadBarrierSlow(
   4578           //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
   4579           //
   4580           //   // /* HeapReference<Class> */ temp2 = value->klass_
   4581           //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
   4582           //   codegen_->GenerateReadBarrierSlow(
   4583           //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
   4584           //
   4585           //   __ cmp(temp1, ShifterOperand(temp2));
   4586           //
   4587           // However, the second read barrier may trash `temp`, as it
   4588           // is a temporary register, and as such would not be saved
   4589           // along with live registers before calling the runtime (nor
   4590           // restored afterwards).  So in this case, we bail out and
   4591           // delegate the work to the array set slow path.
   4592           //
   4593           // TODO: Extend the register allocator to support a new
   4594           // "(locally) live temp" location so as to avoid always
   4595           // going into the slow path when read barriers are enabled.
   4596           __ b(slow_path->GetEntryLabel());
   4597         } else {
   4598           // /* HeapReference<Class> */ temp1 = array->klass_
   4599           __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
   4600           codegen_->MaybeRecordImplicitNullCheck(instruction);
   4601           __ MaybeUnpoisonHeapReference(temp1);
   4602 
   4603           // /* HeapReference<Class> */ temp1 = temp1->component_type_
   4604           __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
   4605           // /* HeapReference<Class> */ temp2 = value->klass_
   4606           __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
   4607           // If heap poisoning is enabled, no need to unpoison `temp1`
   4608           // nor `temp2`, as we are comparing two poisoned references.
   4609           __ cmp(temp1, ShifterOperand(temp2));
   4610 
   4611           if (instruction->StaticTypeOfArrayIsObjectArray()) {
   4612             Label do_put;
   4613             __ b(&do_put, EQ);
   4614             // If heap poisoning is enabled, the `temp1` reference has
   4615             // not been unpoisoned yet; unpoison it now.
   4616             __ MaybeUnpoisonHeapReference(temp1);
   4617 
   4618             // /* HeapReference<Class> */ temp1 = temp1->super_class_
   4619             __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
   4620             // If heap poisoning is enabled, no need to unpoison
   4621             // `temp1`, as we are comparing against null below.
   4622             __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
   4623             __ Bind(&do_put);
   4624           } else {
   4625             __ b(slow_path->GetEntryLabel(), NE);
   4626           }
   4627         }
   4628       }
   4629 
   4630       if (kPoisonHeapReferences) {
   4631         // Note that in the case where `value` is a null reference,
   4632         // we do not enter this block, as a null reference does not
   4633         // need poisoning.
   4634         DCHECK_EQ(value_type, Primitive::kPrimNot);
   4635         __ Mov(temp1, value);
   4636         __ PoisonHeapReference(temp1);
   4637         source = temp1;
   4638       }
   4639 
   4640       if (index.IsConstant()) {
   4641         size_t offset =
   4642             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4643         __ StoreToOffset(kStoreWord, source, array, offset);
   4644       } else {
   4645         DCHECK(index.IsRegister()) << index;
   4646         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4647         __ StoreToOffset(kStoreWord, source, IP, data_offset);
   4648       }
   4649 
   4650       if (!may_need_runtime_call_for_type_check) {
   4651         codegen_->MaybeRecordImplicitNullCheck(instruction);
   4652       }
   4653 
   4654       codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
   4655 
   4656       if (done.IsLinked()) {
   4657         __ Bind(&done);
   4658       }
   4659 
   4660       if (slow_path != nullptr) {
   4661         __ Bind(slow_path->GetExitLabel());
   4662       }
   4663 
   4664       break;
   4665     }
   4666 
   4667     case Primitive::kPrimInt: {
   4668       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
   4669       Register value = locations->InAt(2).AsRegister<Register>();
   4670       if (index.IsConstant()) {
   4671         size_t offset =
   4672             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4673         __ StoreToOffset(kStoreWord, value, array, offset);
   4674       } else {
   4675         DCHECK(index.IsRegister()) << index;
   4676         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4677         __ StoreToOffset(kStoreWord, value, IP, data_offset);
   4678       }
   4679       break;
   4680     }
   4681 
   4682     case Primitive::kPrimLong: {
   4683       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
   4684       Location value = locations->InAt(2);
   4685       if (index.IsConstant()) {
   4686         size_t offset =
   4687             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4688         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
   4689       } else {
   4690         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4691         __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
   4692       }
   4693       break;
   4694     }
   4695 
   4696     case Primitive::kPrimFloat: {
   4697       uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
   4698       Location value = locations->InAt(2);
   4699       DCHECK(value.IsFpuRegister());
   4700       if (index.IsConstant()) {
   4701         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
   4702         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
   4703       } else {
   4704         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   4705         __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
   4706       }
   4707       break;
   4708     }
   4709 
   4710     case Primitive::kPrimDouble: {
   4711       uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
   4712       Location value = locations->InAt(2);
   4713       DCHECK(value.IsFpuRegisterPair());
   4714       if (index.IsConstant()) {
   4715         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
   4716         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
   4717       } else {
   4718         __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
   4719         __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
   4720       }
   4721 
   4722       break;
   4723     }
   4724 
   4725     case Primitive::kPrimVoid:
   4726       LOG(FATAL) << "Unreachable type " << value_type;
   4727       UNREACHABLE();
   4728   }
   4729 
   4730   // Objects are handled in the switch.
   4731   if (value_type != Primitive::kPrimNot) {
   4732     codegen_->MaybeRecordImplicitNullCheck(instruction);
   4733   }
   4734 }
   4735 
   4736 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
   4737   LocationSummary* locations =
   4738       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   4739   locations->SetInAt(0, Location::RequiresRegister());
   4740   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   4741 }
   4742 
   4743 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
   4744   LocationSummary* locations = instruction->GetLocations();
   4745   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
   4746   Register obj = locations->InAt(0).AsRegister<Register>();
   4747   Register out = locations->Out().AsRegister<Register>();
   4748   __ LoadFromOffset(kLoadWord, out, obj, offset);
   4749   codegen_->MaybeRecordImplicitNullCheck(instruction);
   4750 }
   4751 
   4752 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
   4753   LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
   4754       ? LocationSummary::kCallOnSlowPath
   4755       : LocationSummary::kNoCall;
   4756   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   4757   locations->SetInAt(0, Location::RequiresRegister());
   4758   locations->SetInAt(1, Location::RequiresRegister());
   4759   if (instruction->HasUses()) {
   4760     locations->SetOut(Location::SameAsFirstInput());
   4761   }
   4762 }
   4763 
   4764 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
   4765   LocationSummary* locations = instruction->GetLocations();
   4766   SlowPathCode* slow_path =
   4767       new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
   4768   codegen_->AddSlowPath(slow_path);
   4769 
   4770   Register index = locations->InAt(0).AsRegister<Register>();
   4771   Register length = locations->InAt(1).AsRegister<Register>();
   4772 
   4773   __ cmp(index, ShifterOperand(length));
   4774   __ b(slow_path->GetEntryLabel(), HS);
   4775 }
   4776 
   4777 void CodeGeneratorARM::MarkGCCard(Register temp,
   4778                                   Register card,
   4779                                   Register object,
   4780                                   Register value,
   4781                                   bool can_be_null) {
   4782   Label is_null;
   4783   if (can_be_null) {
   4784     __ CompareAndBranchIfZero(value, &is_null);
   4785   }
   4786   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
   4787   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   4788   __ strb(card, Address(card, temp));
   4789   if (can_be_null) {
   4790     __ Bind(&is_null);
   4791   }
   4792 }
   4793 
   4794 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
   4795   LOG(FATAL) << "Unreachable";
   4796 }
   4797 
   4798 void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
   4799   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
   4800 }
   4801 
   4802 void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
   4803   new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
   4804 }
   4805 
   4806 void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
   4807   HBasicBlock* block = instruction->GetBlock();
   4808   if (block->GetLoopInformation() != nullptr) {
   4809     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
   4810     // The back edge will generate the suspend check.
   4811     return;
   4812   }
   4813   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
   4814     // The goto will generate the suspend check.
   4815     return;
   4816   }
   4817   GenerateSuspendCheck(instruction, nullptr);
   4818 }
   4819 
   4820 void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
   4821                                                        HBasicBlock* successor) {
   4822   SuspendCheckSlowPathARM* slow_path =
   4823       down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
   4824   if (slow_path == nullptr) {
   4825     slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
   4826     instruction->SetSlowPath(slow_path);
   4827     codegen_->AddSlowPath(slow_path);
   4828     if (successor != nullptr) {
   4829       DCHECK(successor->IsLoopHeader());
   4830       codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
   4831     }
   4832   } else {
   4833     DCHECK_EQ(slow_path->GetSuccessor(), successor);
   4834   }
   4835 
   4836   __ LoadFromOffset(
   4837       kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
   4838   if (successor == nullptr) {
   4839     __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
   4840     __ Bind(slow_path->GetReturnLabel());
   4841   } else {
   4842     __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
   4843     __ b(slow_path->GetEntryLabel());
   4844   }
   4845 }
   4846 
   4847 ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
   4848   return codegen_->GetAssembler();
   4849 }
   4850 
   4851 void ParallelMoveResolverARM::EmitMove(size_t index) {
   4852   MoveOperands* move = moves_[index];
   4853   Location source = move->GetSource();
   4854   Location destination = move->GetDestination();
   4855 
   4856   if (source.IsRegister()) {
   4857     if (destination.IsRegister()) {
   4858       __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
   4859     } else if (destination.IsFpuRegister()) {
   4860       __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
   4861     } else {
   4862       DCHECK(destination.IsStackSlot());
   4863       __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
   4864                        SP, destination.GetStackIndex());
   4865     }
   4866   } else if (source.IsStackSlot()) {
   4867     if (destination.IsRegister()) {
   4868       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
   4869                         SP, source.GetStackIndex());
   4870     } else if (destination.IsFpuRegister()) {
   4871       __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
   4872     } else {
   4873       DCHECK(destination.IsStackSlot());
   4874       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
   4875       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4876     }
   4877   } else if (source.IsFpuRegister()) {
   4878     if (destination.IsRegister()) {
   4879       __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
   4880     } else if (destination.IsFpuRegister()) {
   4881       __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
   4882     } else {
   4883       DCHECK(destination.IsStackSlot());
   4884       __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
   4885     }
   4886   } else if (source.IsDoubleStackSlot()) {
   4887     if (destination.IsDoubleStackSlot()) {
   4888       __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
   4889       __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
   4890     } else if (destination.IsRegisterPair()) {
   4891       DCHECK(ExpectedPairLayout(destination));
   4892       __ LoadFromOffset(
   4893           kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
   4894     } else {
   4895       DCHECK(destination.IsFpuRegisterPair()) << destination;
   4896       __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4897                          SP,
   4898                          source.GetStackIndex());
   4899     }
   4900   } else if (source.IsRegisterPair()) {
   4901     if (destination.IsRegisterPair()) {
   4902       __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
   4903       __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
   4904     } else if (destination.IsFpuRegisterPair()) {
   4905       __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4906                  source.AsRegisterPairLow<Register>(),
   4907                  source.AsRegisterPairHigh<Register>());
   4908     } else {
   4909       DCHECK(destination.IsDoubleStackSlot()) << destination;
   4910       DCHECK(ExpectedPairLayout(source));
   4911       __ StoreToOffset(
   4912           kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
   4913     }
   4914   } else if (source.IsFpuRegisterPair()) {
   4915     if (destination.IsRegisterPair()) {
   4916       __ vmovrrd(destination.AsRegisterPairLow<Register>(),
   4917                  destination.AsRegisterPairHigh<Register>(),
   4918                  FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
   4919     } else if (destination.IsFpuRegisterPair()) {
   4920       __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
   4921                FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
   4922     } else {
   4923       DCHECK(destination.IsDoubleStackSlot()) << destination;
   4924       __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
   4925                         SP,
   4926                         destination.GetStackIndex());
   4927     }
   4928   } else {
   4929     DCHECK(source.IsConstant()) << source;
   4930     HConstant* constant = source.GetConstant();
   4931     if (constant->IsIntConstant() || constant->IsNullConstant()) {
   4932       int32_t value = CodeGenerator::GetInt32ValueOf(constant);
   4933       if (destination.IsRegister()) {
   4934         __ LoadImmediate(destination.AsRegister<Register>(), value);
   4935       } else {
   4936         DCHECK(destination.IsStackSlot());
   4937         __ LoadImmediate(IP, value);
   4938         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4939       }
   4940     } else if (constant->IsLongConstant()) {
   4941       int64_t value = constant->AsLongConstant()->GetValue();
   4942       if (destination.IsRegisterPair()) {
   4943         __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
   4944         __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
   4945       } else {
   4946         DCHECK(destination.IsDoubleStackSlot()) << destination;
   4947         __ LoadImmediate(IP, Low32Bits(value));
   4948         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4949         __ LoadImmediate(IP, High32Bits(value));
   4950         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
   4951       }
   4952     } else if (constant->IsDoubleConstant()) {
   4953       double value = constant->AsDoubleConstant()->GetValue();
   4954       if (destination.IsFpuRegisterPair()) {
   4955         __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
   4956       } else {
   4957         DCHECK(destination.IsDoubleStackSlot()) << destination;
   4958         uint64_t int_value = bit_cast<uint64_t, double>(value);
   4959         __ LoadImmediate(IP, Low32Bits(int_value));
   4960         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4961         __ LoadImmediate(IP, High32Bits(int_value));
   4962         __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
   4963       }
   4964     } else {
   4965       DCHECK(constant->IsFloatConstant()) << constant->DebugName();
   4966       float value = constant->AsFloatConstant()->GetValue();
   4967       if (destination.IsFpuRegister()) {
   4968         __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
   4969       } else {
   4970         DCHECK(destination.IsStackSlot());
   4971         __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
   4972         __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
   4973       }
   4974     }
   4975   }
   4976 }
   4977 
   4978 void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
   4979   __ Mov(IP, reg);
   4980   __ LoadFromOffset(kLoadWord, reg, SP, mem);
   4981   __ StoreToOffset(kStoreWord, IP, SP, mem);
   4982 }
   4983 
   4984 void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
   4985   ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
   4986   int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
   4987   __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
   4988                     SP, mem1 + stack_offset);
   4989   __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
   4990   __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
   4991                    SP, mem2 + stack_offset);
   4992   __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
   4993 }
   4994 
   4995 void ParallelMoveResolverARM::EmitSwap(size_t index) {
   4996   MoveOperands* move = moves_[index];
   4997   Location source = move->GetSource();
   4998   Location destination = move->GetDestination();
   4999 
   5000   if (source.IsRegister() && destination.IsRegister()) {
   5001     DCHECK_NE(source.AsRegister<Register>(), IP);
   5002     DCHECK_NE(destination.AsRegister<Register>(), IP);
   5003     __ Mov(IP, source.AsRegister<Register>());
   5004     __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
   5005     __ Mov(destination.AsRegister<Register>(), IP);
   5006   } else if (source.IsRegister() && destination.IsStackSlot()) {
   5007     Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
   5008   } else if (source.IsStackSlot() && destination.IsRegister()) {
   5009     Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
   5010   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
   5011     Exchange(source.GetStackIndex(), destination.GetStackIndex());
   5012   } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
   5013     __ vmovrs(IP, source.AsFpuRegister<SRegister>());
   5014     __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
   5015     __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
   5016   } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
   5017     __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
   5018     __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
   5019     __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
   5020     __ vmovrrd(destination.AsRegisterPairLow<Register>(),
   5021                destination.AsRegisterPairHigh<Register>(),
   5022                DTMP);
   5023   } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
   5024     Register low_reg = source.IsRegisterPair()
   5025         ? source.AsRegisterPairLow<Register>()
   5026         : destination.AsRegisterPairLow<Register>();
   5027     int mem = source.IsRegisterPair()
   5028         ? destination.GetStackIndex()
   5029         : source.GetStackIndex();
   5030     DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
   5031     __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
   5032     __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
   5033     __ StoreDToOffset(DTMP, SP, mem);
   5034   } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
   5035     DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
   5036     DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
   5037     __ vmovd(DTMP, first);
   5038     __ vmovd(first, second);
   5039     __ vmovd(second, DTMP);
   5040   } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
   5041     DRegister reg = source.IsFpuRegisterPair()
   5042         ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
   5043         : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
   5044     int mem = source.IsFpuRegisterPair()
   5045         ? destination.GetStackIndex()
   5046         : source.GetStackIndex();
   5047     __ vmovd(DTMP, reg);
   5048     __ LoadDFromOffset(reg, SP, mem);
   5049     __ StoreDToOffset(DTMP, SP, mem);
   5050   } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
   5051     SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
   5052                                            : destination.AsFpuRegister<SRegister>();
   5053     int mem = source.IsFpuRegister()
   5054         ? destination.GetStackIndex()
   5055         : source.GetStackIndex();
   5056 
   5057     __ vmovrs(IP, reg);
   5058     __ LoadSFromOffset(reg, SP, mem);
   5059     __ StoreToOffset(kStoreWord, IP, SP, mem);
   5060   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
   5061     Exchange(source.GetStackIndex(), destination.GetStackIndex());
   5062     Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
   5063   } else {
   5064     LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
   5065   }
   5066 }
   5067 
   5068 void ParallelMoveResolverARM::SpillScratch(int reg) {
   5069   __ Push(static_cast<Register>(reg));
   5070 }
   5071 
   5072 void ParallelMoveResolverARM::RestoreScratch(int reg) {
   5073   __ Pop(static_cast<Register>(reg));
   5074 }
   5075 
   5076 void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
   5077   InvokeRuntimeCallingConvention calling_convention;
   5078   CodeGenerator::CreateLoadClassLocationSummary(
   5079       cls,
   5080       Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
   5081       Location::RegisterLocation(R0),
   5082       /* code_generator_supports_read_barrier */ true);
   5083 }
   5084 
   5085 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
   5086   LocationSummary* locations = cls->GetLocations();
   5087   if (cls->NeedsAccessCheck()) {
   5088     codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
   5089     codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
   5090                             cls,
   5091                             cls->GetDexPc(),
   5092                             nullptr);
   5093     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
   5094     return;
   5095   }
   5096 
   5097   Location out_loc = locations->Out();
   5098   Register out = out_loc.AsRegister<Register>();
   5099   Register current_method = locations->InAt(0).AsRegister<Register>();
   5100 
   5101   if (cls->IsReferrersClass()) {
   5102     DCHECK(!cls->CanCallRuntime());
   5103     DCHECK(!cls->MustGenerateClinitCheck());
   5104     // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
   5105     GenerateGcRootFieldLoad(
   5106         cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   5107   } else {
   5108     // /* GcRoot<mirror::Class>[] */ out =
   5109     //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
   5110     __ LoadFromOffset(kLoadWord,
   5111                       out,
   5112                       current_method,
   5113                       ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
   5114     // /* GcRoot<mirror::Class> */ out = out[type_index]
   5115     GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
   5116 
   5117     if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
   5118       DCHECK(cls->CanCallRuntime());
   5119       SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
   5120           cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
   5121       codegen_->AddSlowPath(slow_path);
   5122       if (!cls->IsInDexCache()) {
   5123         __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
   5124       }
   5125       if (cls->MustGenerateClinitCheck()) {
   5126         GenerateClassInitializationCheck(slow_path, out);
   5127       } else {
   5128         __ Bind(slow_path->GetExitLabel());
   5129       }
   5130     }
   5131   }
   5132 }
   5133 
   5134 void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
   5135   LocationSummary* locations =
   5136       new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
   5137   locations->SetInAt(0, Location::RequiresRegister());
   5138   if (check->HasUses()) {
   5139     locations->SetOut(Location::SameAsFirstInput());
   5140   }
   5141 }
   5142 
   5143 void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
   5144   // We assume the class is not null.
   5145   SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
   5146       check->GetLoadClass(), check, check->GetDexPc(), true);
   5147   codegen_->AddSlowPath(slow_path);
   5148   GenerateClassInitializationCheck(slow_path,
   5149                                    check->GetLocations()->InAt(0).AsRegister<Register>());
   5150 }
   5151 
   5152 void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
   5153     SlowPathCode* slow_path, Register class_reg) {
   5154   __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
   5155   __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
   5156   __ b(slow_path->GetEntryLabel(), LT);
   5157   // Even if the initialized flag is set, we may be in a situation where caches are not synced
   5158   // properly. Therefore, we do a memory fence.
   5159   __ dmb(ISH);
   5160   __ Bind(slow_path->GetExitLabel());
   5161 }
   5162 
   5163 HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
   5164     HLoadString::LoadKind desired_string_load_kind) {
   5165   if (kEmitCompilerReadBarrier) {
   5166     switch (desired_string_load_kind) {
   5167       case HLoadString::LoadKind::kBootImageLinkTimeAddress:
   5168       case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
   5169       case HLoadString::LoadKind::kBootImageAddress:
   5170         // TODO: Implement for read barrier.
   5171         return HLoadString::LoadKind::kDexCacheViaMethod;
   5172       default:
   5173         break;
   5174     }
   5175   }
   5176   switch (desired_string_load_kind) {
   5177     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
   5178       DCHECK(!GetCompilerOptions().GetCompilePic());
   5179       break;
   5180     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
   5181       DCHECK(GetCompilerOptions().GetCompilePic());
   5182       break;
   5183     case HLoadString::LoadKind::kBootImageAddress:
   5184       break;
   5185     case HLoadString::LoadKind::kDexCacheAddress:
   5186       DCHECK(Runtime::Current()->UseJitCompilation());
   5187       break;
   5188     case HLoadString::LoadKind::kDexCachePcRelative:
   5189       DCHECK(!Runtime::Current()->UseJitCompilation());
   5190       // We disable pc-relative load when there is an irreducible loop, as the optimization
   5191       // is incompatible with it.
   5192       // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
   5193       // with irreducible loops.
   5194       if (GetGraph()->HasIrreducibleLoops()) {
   5195         return HLoadString::LoadKind::kDexCacheViaMethod;
   5196       }
   5197       break;
   5198     case HLoadString::LoadKind::kDexCacheViaMethod:
   5199       break;
   5200   }
   5201   return desired_string_load_kind;
   5202 }
   5203 
   5204 void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
   5205   LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
   5206       ? LocationSummary::kCallOnSlowPath
   5207       : LocationSummary::kNoCall;
   5208   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
   5209   HLoadString::LoadKind load_kind = load->GetLoadKind();
   5210   if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
   5211       load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
   5212     locations->SetInAt(0, Location::RequiresRegister());
   5213   }
   5214   locations->SetOut(Location::RequiresRegister());
   5215 }
   5216 
   5217 void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
   5218   LocationSummary* locations = load->GetLocations();
   5219   Location out_loc = locations->Out();
   5220   Register out = out_loc.AsRegister<Register>();
   5221 
   5222   switch (load->GetLoadKind()) {
   5223     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
   5224       DCHECK(!kEmitCompilerReadBarrier);
   5225       __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
   5226                                                                       load->GetStringIndex()));
   5227       return;  // No dex cache slow path.
   5228     }
   5229     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
   5230       DCHECK(!kEmitCompilerReadBarrier);
   5231       CodeGeneratorARM::PcRelativePatchInfo* labels =
   5232           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
   5233       __ BindTrackedLabel(&labels->movw_label);
   5234       __ movw(out, /* placeholder */ 0u);
   5235       __ BindTrackedLabel(&labels->movt_label);
   5236       __ movt(out, /* placeholder */ 0u);
   5237       __ BindTrackedLabel(&labels->add_pc_label);
   5238       __ add(out, out, ShifterOperand(PC));
   5239       return;  // No dex cache slow path.
   5240     }
   5241     case HLoadString::LoadKind::kBootImageAddress: {
   5242       DCHECK(!kEmitCompilerReadBarrier);
   5243       DCHECK_NE(load->GetAddress(), 0u);
   5244       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
   5245       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
   5246       return;  // No dex cache slow path.
   5247     }
   5248     case HLoadString::LoadKind::kDexCacheAddress: {
   5249       DCHECK_NE(load->GetAddress(), 0u);
   5250       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
   5251       // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
   5252       // a 128B range. To try and reduce the number of literals if we load multiple strings,
   5253       // simply split the dex cache address to a 128B aligned base loaded from a literal
   5254       // and the remaining offset embedded in the load.
   5255       static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
   5256       DCHECK_ALIGNED(load->GetAddress(), 4u);
   5257       constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
   5258       uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
   5259       uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
   5260       __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
   5261       GenerateGcRootFieldLoad(load, out_loc, out, offset);
   5262       break;
   5263     }
   5264     case HLoadString::LoadKind::kDexCachePcRelative: {
   5265       Register base_reg = locations->InAt(0).AsRegister<Register>();
   5266       HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
   5267       int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
   5268       GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
   5269       break;
   5270     }
   5271     case HLoadString::LoadKind::kDexCacheViaMethod: {
   5272       Register current_method = locations->InAt(0).AsRegister<Register>();
   5273 
   5274       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
   5275       GenerateGcRootFieldLoad(
   5276           load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   5277       // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
   5278       __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
   5279       // /* GcRoot<mirror::String> */ out = out[string_index]
   5280       GenerateGcRootFieldLoad(
   5281           load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
   5282       break;
   5283     }
   5284     default:
   5285       LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
   5286       UNREACHABLE();
   5287   }
   5288 
   5289   if (!load->IsInDexCache()) {
   5290     SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
   5291     codegen_->AddSlowPath(slow_path);
   5292     __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
   5293     __ Bind(slow_path->GetExitLabel());
   5294   }
   5295 }
   5296 
   5297 static int32_t GetExceptionTlsOffset() {
   5298   return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
   5299 }
   5300 
   5301 void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
   5302   LocationSummary* locations =
   5303       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
   5304   locations->SetOut(Location::RequiresRegister());
   5305 }
   5306 
   5307 void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
   5308   Register out = load->GetLocations()->Out().AsRegister<Register>();
   5309   __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
   5310 }
   5311 
   5312 void LocationsBuilderARM::VisitClearException(HClearException* clear) {
   5313   new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
   5314 }
   5315 
   5316 void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
   5317   __ LoadImmediate(IP, 0);
   5318   __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
   5319 }
   5320 
   5321 void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
   5322   LocationSummary* locations =
   5323       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   5324   InvokeRuntimeCallingConvention calling_convention;
   5325   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   5326 }
   5327 
   5328 void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
   5329   codegen_->InvokeRuntime(
   5330       QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
   5331   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
   5332 }
   5333 
   5334 static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
   5335   return kEmitCompilerReadBarrier &&
   5336       (kUseBakerReadBarrier ||
   5337        type_check_kind == TypeCheckKind::kAbstractClassCheck ||
   5338        type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
   5339        type_check_kind == TypeCheckKind::kArrayObjectCheck);
   5340 }
   5341 
   5342 void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
   5343   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   5344   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5345   switch (type_check_kind) {
   5346     case TypeCheckKind::kExactCheck:
   5347     case TypeCheckKind::kAbstractClassCheck:
   5348     case TypeCheckKind::kClassHierarchyCheck:
   5349     case TypeCheckKind::kArrayObjectCheck:
   5350       call_kind =
   5351           kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
   5352       break;
   5353     case TypeCheckKind::kArrayCheck:
   5354     case TypeCheckKind::kUnresolvedCheck:
   5355     case TypeCheckKind::kInterfaceCheck:
   5356       call_kind = LocationSummary::kCallOnSlowPath;
   5357       break;
   5358   }
   5359 
   5360   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   5361   locations->SetInAt(0, Location::RequiresRegister());
   5362   locations->SetInAt(1, Location::RequiresRegister());
   5363   // The "out" register is used as a temporary, so it overlaps with the inputs.
   5364   // Note that TypeCheckSlowPathARM uses this register too.
   5365   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
   5366   // When read barriers are enabled, we need a temporary register for
   5367   // some cases.
   5368   if (TypeCheckNeedsATemporary(type_check_kind)) {
   5369     locations->AddTemp(Location::RequiresRegister());
   5370   }
   5371 }
   5372 
   5373 void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
   5374   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5375   LocationSummary* locations = instruction->GetLocations();
   5376   Location obj_loc = locations->InAt(0);
   5377   Register obj = obj_loc.AsRegister<Register>();
   5378   Register cls = locations->InAt(1).AsRegister<Register>();
   5379   Location out_loc = locations->Out();
   5380   Register out = out_loc.AsRegister<Register>();
   5381   Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
   5382       locations->GetTemp(0) :
   5383       Location::NoLocation();
   5384   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   5385   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   5386   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   5387   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
   5388   Label done, zero;
   5389   SlowPathCode* slow_path = nullptr;
   5390 
   5391   // Return 0 if `obj` is null.
   5392   // avoid null check if we know obj is not null.
   5393   if (instruction->MustDoNullCheck()) {
   5394     __ CompareAndBranchIfZero(obj, &zero);
   5395   }
   5396 
   5397   // /* HeapReference<Class> */ out = obj->klass_
   5398   GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
   5399 
   5400   switch (type_check_kind) {
   5401     case TypeCheckKind::kExactCheck: {
   5402       __ cmp(out, ShifterOperand(cls));
   5403       // Classes must be equal for the instanceof to succeed.
   5404       __ b(&zero, NE);
   5405       __ LoadImmediate(out, 1);
   5406       __ b(&done);
   5407       break;
   5408     }
   5409 
   5410     case TypeCheckKind::kAbstractClassCheck: {
   5411       // If the class is abstract, we eagerly fetch the super class of the
   5412       // object to avoid doing a comparison we know will fail.
   5413       Label loop;
   5414       __ Bind(&loop);
   5415       // /* HeapReference<Class> */ out = out->super_class_
   5416       GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
   5417       // If `out` is null, we use it for the result, and jump to `done`.
   5418       __ CompareAndBranchIfZero(out, &done);
   5419       __ cmp(out, ShifterOperand(cls));
   5420       __ b(&loop, NE);
   5421       __ LoadImmediate(out, 1);
   5422       if (zero.IsLinked()) {
   5423         __ b(&done);
   5424       }
   5425       break;
   5426     }
   5427 
   5428     case TypeCheckKind::kClassHierarchyCheck: {
   5429       // Walk over the class hierarchy to find a match.
   5430       Label loop, success;
   5431       __ Bind(&loop);
   5432       __ cmp(out, ShifterOperand(cls));
   5433       __ b(&success, EQ);
   5434       // /* HeapReference<Class> */ out = out->super_class_
   5435       GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
   5436       __ CompareAndBranchIfNonZero(out, &loop);
   5437       // If `out` is null, we use it for the result, and jump to `done`.
   5438       __ b(&done);
   5439       __ Bind(&success);
   5440       __ LoadImmediate(out, 1);
   5441       if (zero.IsLinked()) {
   5442         __ b(&done);
   5443       }
   5444       break;
   5445     }
   5446 
   5447     case TypeCheckKind::kArrayObjectCheck: {
   5448       // Do an exact check.
   5449       Label exact_check;
   5450       __ cmp(out, ShifterOperand(cls));
   5451       __ b(&exact_check, EQ);
   5452       // Otherwise, we need to check that the object's class is a non-primitive array.
   5453       // /* HeapReference<Class> */ out = out->component_type_
   5454       GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
   5455       // If `out` is null, we use it for the result, and jump to `done`.
   5456       __ CompareAndBranchIfZero(out, &done);
   5457       __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
   5458       static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
   5459       __ CompareAndBranchIfNonZero(out, &zero);
   5460       __ Bind(&exact_check);
   5461       __ LoadImmediate(out, 1);
   5462       __ b(&done);
   5463       break;
   5464     }
   5465 
   5466     case TypeCheckKind::kArrayCheck: {
   5467       __ cmp(out, ShifterOperand(cls));
   5468       DCHECK(locations->OnlyCallsOnSlowPath());
   5469       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5470                                                                     /* is_fatal */ false);
   5471       codegen_->AddSlowPath(slow_path);
   5472       __ b(slow_path->GetEntryLabel(), NE);
   5473       __ LoadImmediate(out, 1);
   5474       if (zero.IsLinked()) {
   5475         __ b(&done);
   5476       }
   5477       break;
   5478     }
   5479 
   5480     case TypeCheckKind::kUnresolvedCheck:
   5481     case TypeCheckKind::kInterfaceCheck: {
   5482       // Note that we indeed only call on slow path, but we always go
   5483       // into the slow path for the unresolved and interface check
   5484       // cases.
   5485       //
   5486       // We cannot directly call the InstanceofNonTrivial runtime
   5487       // entry point without resorting to a type checking slow path
   5488       // here (i.e. by calling InvokeRuntime directly), as it would
   5489       // require to assign fixed registers for the inputs of this
   5490       // HInstanceOf instruction (following the runtime calling
   5491       // convention), which might be cluttered by the potential first
   5492       // read barrier emission at the beginning of this method.
   5493       //
   5494       // TODO: Introduce a new runtime entry point taking the object
   5495       // to test (instead of its class) as argument, and let it deal
   5496       // with the read barrier issues. This will let us refactor this
   5497       // case of the `switch` code as it was previously (with a direct
   5498       // call to the runtime not using a type checking slow path).
   5499       // This should also be beneficial for the other cases above.
   5500       DCHECK(locations->OnlyCallsOnSlowPath());
   5501       slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5502                                                                     /* is_fatal */ false);
   5503       codegen_->AddSlowPath(slow_path);
   5504       __ b(slow_path->GetEntryLabel());
   5505       if (zero.IsLinked()) {
   5506         __ b(&done);
   5507       }
   5508       break;
   5509     }
   5510   }
   5511 
   5512   if (zero.IsLinked()) {
   5513     __ Bind(&zero);
   5514     __ LoadImmediate(out, 0);
   5515   }
   5516 
   5517   if (done.IsLinked()) {
   5518     __ Bind(&done);
   5519   }
   5520 
   5521   if (slow_path != nullptr) {
   5522     __ Bind(slow_path->GetExitLabel());
   5523   }
   5524 }
   5525 
   5526 void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
   5527   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   5528   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
   5529 
   5530   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5531   switch (type_check_kind) {
   5532     case TypeCheckKind::kExactCheck:
   5533     case TypeCheckKind::kAbstractClassCheck:
   5534     case TypeCheckKind::kClassHierarchyCheck:
   5535     case TypeCheckKind::kArrayObjectCheck:
   5536       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
   5537           LocationSummary::kCallOnSlowPath :
   5538           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
   5539       break;
   5540     case TypeCheckKind::kArrayCheck:
   5541     case TypeCheckKind::kUnresolvedCheck:
   5542     case TypeCheckKind::kInterfaceCheck:
   5543       call_kind = LocationSummary::kCallOnSlowPath;
   5544       break;
   5545   }
   5546 
   5547   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
   5548   locations->SetInAt(0, Location::RequiresRegister());
   5549   locations->SetInAt(1, Location::RequiresRegister());
   5550   // Note that TypeCheckSlowPathARM uses this "temp" register too.
   5551   locations->AddTemp(Location::RequiresRegister());
   5552   // When read barriers are enabled, we need an additional temporary
   5553   // register for some cases.
   5554   if (TypeCheckNeedsATemporary(type_check_kind)) {
   5555     locations->AddTemp(Location::RequiresRegister());
   5556   }
   5557 }
   5558 
   5559 void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
   5560   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
   5561   LocationSummary* locations = instruction->GetLocations();
   5562   Location obj_loc = locations->InAt(0);
   5563   Register obj = obj_loc.AsRegister<Register>();
   5564   Register cls = locations->InAt(1).AsRegister<Register>();
   5565   Location temp_loc = locations->GetTemp(0);
   5566   Register temp = temp_loc.AsRegister<Register>();
   5567   Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
   5568       locations->GetTemp(1) :
   5569       Location::NoLocation();
   5570   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   5571   uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
   5572   uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
   5573   uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
   5574 
   5575   bool is_type_check_slow_path_fatal =
   5576       (type_check_kind == TypeCheckKind::kExactCheck ||
   5577        type_check_kind == TypeCheckKind::kAbstractClassCheck ||
   5578        type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
   5579        type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
   5580       !instruction->CanThrowIntoCatchBlock();
   5581   SlowPathCode* type_check_slow_path =
   5582       new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
   5583                                                         is_type_check_slow_path_fatal);
   5584   codegen_->AddSlowPath(type_check_slow_path);
   5585 
   5586   Label done;
   5587   // Avoid null check if we know obj is not null.
   5588   if (instruction->MustDoNullCheck()) {
   5589     __ CompareAndBranchIfZero(obj, &done);
   5590   }
   5591 
   5592   // /* HeapReference<Class> */ temp = obj->klass_
   5593   GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5594 
   5595   switch (type_check_kind) {
   5596     case TypeCheckKind::kExactCheck:
   5597     case TypeCheckKind::kArrayCheck: {
   5598       __ cmp(temp, ShifterOperand(cls));
   5599       // Jump to slow path for throwing the exception or doing a
   5600       // more involved array check.
   5601       __ b(type_check_slow_path->GetEntryLabel(), NE);
   5602       break;
   5603     }
   5604 
   5605     case TypeCheckKind::kAbstractClassCheck: {
   5606       // If the class is abstract, we eagerly fetch the super class of the
   5607       // object to avoid doing a comparison we know will fail.
   5608       Label loop, compare_classes;
   5609       __ Bind(&loop);
   5610       // /* HeapReference<Class> */ temp = temp->super_class_
   5611       GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
   5612 
   5613       // If the class reference currently in `temp` is not null, jump
   5614       // to the `compare_classes` label to compare it with the checked
   5615       // class.
   5616       __ CompareAndBranchIfNonZero(temp, &compare_classes);
   5617       // Otherwise, jump to the slow path to throw the exception.
   5618       //
   5619       // But before, move back the object's class into `temp` before
   5620       // going into the slow path, as it has been overwritten in the
   5621       // meantime.
   5622       // /* HeapReference<Class> */ temp = obj->klass_
   5623       GenerateReferenceLoadTwoRegisters(
   5624           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5625       __ b(type_check_slow_path->GetEntryLabel());
   5626 
   5627       __ Bind(&compare_classes);
   5628       __ cmp(temp, ShifterOperand(cls));
   5629       __ b(&loop, NE);
   5630       break;
   5631     }
   5632 
   5633     case TypeCheckKind::kClassHierarchyCheck: {
   5634       // Walk over the class hierarchy to find a match.
   5635       Label loop;
   5636       __ Bind(&loop);
   5637       __ cmp(temp, ShifterOperand(cls));
   5638       __ b(&done, EQ);
   5639 
   5640       // /* HeapReference<Class> */ temp = temp->super_class_
   5641       GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
   5642 
   5643       // If the class reference currently in `temp` is not null, jump
   5644       // back at the beginning of the loop.
   5645       __ CompareAndBranchIfNonZero(temp, &loop);
   5646       // Otherwise, jump to the slow path to throw the exception.
   5647       //
   5648       // But before, move back the object's class into `temp` before
   5649       // going into the slow path, as it has been overwritten in the
   5650       // meantime.
   5651       // /* HeapReference<Class> */ temp = obj->klass_
   5652       GenerateReferenceLoadTwoRegisters(
   5653           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5654       __ b(type_check_slow_path->GetEntryLabel());
   5655       break;
   5656     }
   5657 
   5658     case TypeCheckKind::kArrayObjectCheck: {
   5659       // Do an exact check.
   5660       Label check_non_primitive_component_type;
   5661       __ cmp(temp, ShifterOperand(cls));
   5662       __ b(&done, EQ);
   5663 
   5664       // Otherwise, we need to check that the object's class is a non-primitive array.
   5665       // /* HeapReference<Class> */ temp = temp->component_type_
   5666       GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
   5667 
   5668       // If the component type is not null (i.e. the object is indeed
   5669       // an array), jump to label `check_non_primitive_component_type`
   5670       // to further check that this component type is not a primitive
   5671       // type.
   5672       __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
   5673       // Otherwise, jump to the slow path to throw the exception.
   5674       //
   5675       // But before, move back the object's class into `temp` before
   5676       // going into the slow path, as it has been overwritten in the
   5677       // meantime.
   5678       // /* HeapReference<Class> */ temp = obj->klass_
   5679       GenerateReferenceLoadTwoRegisters(
   5680           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5681       __ b(type_check_slow_path->GetEntryLabel());
   5682 
   5683       __ Bind(&check_non_primitive_component_type);
   5684       __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
   5685       static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
   5686       __ CompareAndBranchIfZero(temp, &done);
   5687       // Same comment as above regarding `temp` and the slow path.
   5688       // /* HeapReference<Class> */ temp = obj->klass_
   5689       GenerateReferenceLoadTwoRegisters(
   5690           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
   5691       __ b(type_check_slow_path->GetEntryLabel());
   5692       break;
   5693     }
   5694 
   5695     case TypeCheckKind::kUnresolvedCheck:
   5696     case TypeCheckKind::kInterfaceCheck:
   5697       // We always go into the type check slow path for the unresolved
   5698       // and interface check cases.
   5699       //
   5700       // We cannot directly call the CheckCast runtime entry point
   5701       // without resorting to a type checking slow path here (i.e. by
   5702       // calling InvokeRuntime directly), as it would require to
   5703       // assign fixed registers for the inputs of this HInstanceOf
   5704       // instruction (following the runtime calling convention), which
   5705       // might be cluttered by the potential first read barrier
   5706       // emission at the beginning of this method.
   5707       //
   5708       // TODO: Introduce a new runtime entry point taking the object
   5709       // to test (instead of its class) as argument, and let it deal
   5710       // with the read barrier issues. This will let us refactor this
   5711       // case of the `switch` code as it was previously (with a direct
   5712       // call to the runtime not using a type checking slow path).
   5713       // This should also be beneficial for the other cases above.
   5714       __ b(type_check_slow_path->GetEntryLabel());
   5715       break;
   5716   }
   5717   __ Bind(&done);
   5718 
   5719   __ Bind(type_check_slow_path->GetExitLabel());
   5720 }
   5721 
   5722 void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
   5723   LocationSummary* locations =
   5724       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   5725   InvokeRuntimeCallingConvention calling_convention;
   5726   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   5727 }
   5728 
   5729 void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
   5730   codegen_->InvokeRuntime(instruction->IsEnter()
   5731         ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
   5732       instruction,
   5733       instruction->GetDexPc(),
   5734       nullptr);
   5735   if (instruction->IsEnter()) {
   5736     CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
   5737   } else {
   5738     CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
   5739   }
   5740 }
   5741 
   5742 void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
   5743 void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
   5744 void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
   5745 
   5746 void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
   5747   LocationSummary* locations =
   5748       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   5749   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
   5750          || instruction->GetResultType() == Primitive::kPrimLong);
   5751   // Note: GVN reorders commutative operations to have the constant on the right hand side.
   5752   locations->SetInAt(0, Location::RequiresRegister());
   5753   locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
   5754   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   5755 }
   5756 
   5757 void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
   5758   HandleBitwiseOperation(instruction);
   5759 }
   5760 
   5761 void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
   5762   HandleBitwiseOperation(instruction);
   5763 }
   5764 
   5765 void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
   5766   HandleBitwiseOperation(instruction);
   5767 }
   5768 
   5769 
   5770 void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
   5771   LocationSummary* locations =
   5772       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   5773   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
   5774          || instruction->GetResultType() == Primitive::kPrimLong);
   5775 
   5776   locations->SetInAt(0, Location::RequiresRegister());
   5777   locations->SetInAt(1, Location::RequiresRegister());
   5778   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   5779 }
   5780 
   5781 void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
   5782   LocationSummary* locations = instruction->GetLocations();
   5783   Location first = locations->InAt(0);
   5784   Location second = locations->InAt(1);
   5785   Location out = locations->Out();
   5786 
   5787   if (instruction->GetResultType() == Primitive::kPrimInt) {
   5788     Register first_reg = first.AsRegister<Register>();
   5789     ShifterOperand second_reg(second.AsRegister<Register>());
   5790     Register out_reg = out.AsRegister<Register>();
   5791 
   5792     switch (instruction->GetOpKind()) {
   5793       case HInstruction::kAnd:
   5794         __ bic(out_reg, first_reg, second_reg);
   5795         break;
   5796       case HInstruction::kOr:
   5797         __ orn(out_reg, first_reg, second_reg);
   5798         break;
   5799       // There is no EON on arm.
   5800       case HInstruction::kXor:
   5801       default:
   5802         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
   5803         UNREACHABLE();
   5804     }
   5805     return;
   5806 
   5807   } else {
   5808     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5809     Register first_low = first.AsRegisterPairLow<Register>();
   5810     Register first_high = first.AsRegisterPairHigh<Register>();
   5811     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
   5812     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
   5813     Register out_low = out.AsRegisterPairLow<Register>();
   5814     Register out_high = out.AsRegisterPairHigh<Register>();
   5815 
   5816     switch (instruction->GetOpKind()) {
   5817       case HInstruction::kAnd:
   5818         __ bic(out_low, first_low, second_low);
   5819         __ bic(out_high, first_high, second_high);
   5820         break;
   5821       case HInstruction::kOr:
   5822         __ orn(out_low, first_low, second_low);
   5823         __ orn(out_high, first_high, second_high);
   5824         break;
   5825       // There is no EON on arm.
   5826       case HInstruction::kXor:
   5827       default:
   5828         LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
   5829         UNREACHABLE();
   5830     }
   5831   }
   5832 }
   5833 
   5834 void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
   5835   // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
   5836   if (value == 0xffffffffu) {
   5837     if (out != first) {
   5838       __ mov(out, ShifterOperand(first));
   5839     }
   5840     return;
   5841   }
   5842   if (value == 0u) {
   5843     __ mov(out, ShifterOperand(0));
   5844     return;
   5845   }
   5846   ShifterOperand so;
   5847   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
   5848     __ and_(out, first, so);
   5849   } else {
   5850     DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
   5851     __ bic(out, first, ShifterOperand(~value));
   5852   }
   5853 }
   5854 
   5855 void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
   5856   // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
   5857   if (value == 0u) {
   5858     if (out != first) {
   5859       __ mov(out, ShifterOperand(first));
   5860     }
   5861     return;
   5862   }
   5863   if (value == 0xffffffffu) {
   5864     __ mvn(out, ShifterOperand(0));
   5865     return;
   5866   }
   5867   ShifterOperand so;
   5868   if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
   5869     __ orr(out, first, so);
   5870   } else {
   5871     DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
   5872     __ orn(out, first, ShifterOperand(~value));
   5873   }
   5874 }
   5875 
   5876 void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
   5877   // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
   5878   if (value == 0u) {
   5879     if (out != first) {
   5880       __ mov(out, ShifterOperand(first));
   5881     }
   5882     return;
   5883   }
   5884   __ eor(out, first, ShifterOperand(value));
   5885 }
   5886 
   5887 void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
   5888   LocationSummary* locations = instruction->GetLocations();
   5889   Location first = locations->InAt(0);
   5890   Location second = locations->InAt(1);
   5891   Location out = locations->Out();
   5892 
   5893   if (second.IsConstant()) {
   5894     uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
   5895     uint32_t value_low = Low32Bits(value);
   5896     if (instruction->GetResultType() == Primitive::kPrimInt) {
   5897       Register first_reg = first.AsRegister<Register>();
   5898       Register out_reg = out.AsRegister<Register>();
   5899       if (instruction->IsAnd()) {
   5900         GenerateAndConst(out_reg, first_reg, value_low);
   5901       } else if (instruction->IsOr()) {
   5902         GenerateOrrConst(out_reg, first_reg, value_low);
   5903       } else {
   5904         DCHECK(instruction->IsXor());
   5905         GenerateEorConst(out_reg, first_reg, value_low);
   5906       }
   5907     } else {
   5908       DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5909       uint32_t value_high = High32Bits(value);
   5910       Register first_low = first.AsRegisterPairLow<Register>();
   5911       Register first_high = first.AsRegisterPairHigh<Register>();
   5912       Register out_low = out.AsRegisterPairLow<Register>();
   5913       Register out_high = out.AsRegisterPairHigh<Register>();
   5914       if (instruction->IsAnd()) {
   5915         GenerateAndConst(out_low, first_low, value_low);
   5916         GenerateAndConst(out_high, first_high, value_high);
   5917       } else if (instruction->IsOr()) {
   5918         GenerateOrrConst(out_low, first_low, value_low);
   5919         GenerateOrrConst(out_high, first_high, value_high);
   5920       } else {
   5921         DCHECK(instruction->IsXor());
   5922         GenerateEorConst(out_low, first_low, value_low);
   5923         GenerateEorConst(out_high, first_high, value_high);
   5924       }
   5925     }
   5926     return;
   5927   }
   5928 
   5929   if (instruction->GetResultType() == Primitive::kPrimInt) {
   5930     Register first_reg = first.AsRegister<Register>();
   5931     ShifterOperand second_reg(second.AsRegister<Register>());
   5932     Register out_reg = out.AsRegister<Register>();
   5933     if (instruction->IsAnd()) {
   5934       __ and_(out_reg, first_reg, second_reg);
   5935     } else if (instruction->IsOr()) {
   5936       __ orr(out_reg, first_reg, second_reg);
   5937     } else {
   5938       DCHECK(instruction->IsXor());
   5939       __ eor(out_reg, first_reg, second_reg);
   5940     }
   5941   } else {
   5942     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
   5943     Register first_low = first.AsRegisterPairLow<Register>();
   5944     Register first_high = first.AsRegisterPairHigh<Register>();
   5945     ShifterOperand second_low(second.AsRegisterPairLow<Register>());
   5946     ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
   5947     Register out_low = out.AsRegisterPairLow<Register>();
   5948     Register out_high = out.AsRegisterPairHigh<Register>();
   5949     if (instruction->IsAnd()) {
   5950       __ and_(out_low, first_low, second_low);
   5951       __ and_(out_high, first_high, second_high);
   5952     } else if (instruction->IsOr()) {
   5953       __ orr(out_low, first_low, second_low);
   5954       __ orr(out_high, first_high, second_high);
   5955     } else {
   5956       DCHECK(instruction->IsXor());
   5957       __ eor(out_low, first_low, second_low);
   5958       __ eor(out_high, first_high, second_high);
   5959     }
   5960   }
   5961 }
   5962 
   5963 void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
   5964                                                                    Location out,
   5965                                                                    uint32_t offset,
   5966                                                                    Location maybe_temp) {
   5967   Register out_reg = out.AsRegister<Register>();
   5968   if (kEmitCompilerReadBarrier) {
   5969     DCHECK(maybe_temp.IsRegister()) << maybe_temp;
   5970     if (kUseBakerReadBarrier) {
   5971       // Load with fast path based Baker's read barrier.
   5972       // /* HeapReference<Object> */ out = *(out + offset)
   5973       codegen_->GenerateFieldLoadWithBakerReadBarrier(
   5974           instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
   5975     } else {
   5976       // Load with slow path based read barrier.
   5977       // Save the value of `out` into `maybe_temp` before overwriting it
   5978       // in the following move operation, as we will need it for the
   5979       // read barrier below.
   5980       __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
   5981       // /* HeapReference<Object> */ out = *(out + offset)
   5982       __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
   5983       codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
   5984     }
   5985   } else {
   5986     // Plain load with no read barrier.
   5987     // /* HeapReference<Object> */ out = *(out + offset)
   5988     __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
   5989     __ MaybeUnpoisonHeapReference(out_reg);
   5990   }
   5991 }
   5992 
   5993 void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
   5994                                                                     Location out,
   5995                                                                     Location obj,
   5996                                                                     uint32_t offset,
   5997                                                                     Location maybe_temp) {
   5998   Register out_reg = out.AsRegister<Register>();
   5999   Register obj_reg = obj.AsRegister<Register>();
   6000   if (kEmitCompilerReadBarrier) {
   6001     if (kUseBakerReadBarrier) {
   6002       DCHECK(maybe_temp.IsRegister()) << maybe_temp;
   6003       // Load with fast path based Baker's read barrier.
   6004       // /* HeapReference<Object> */ out = *(obj + offset)
   6005       codegen_->GenerateFieldLoadWithBakerReadBarrier(
   6006           instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
   6007     } else {
   6008       // Load with slow path based read barrier.
   6009       // /* HeapReference<Object> */ out = *(obj + offset)
   6010       __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
   6011       codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
   6012     }
   6013   } else {
   6014     // Plain load with no read barrier.
   6015     // /* HeapReference<Object> */ out = *(obj + offset)
   6016     __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
   6017     __ MaybeUnpoisonHeapReference(out_reg);
   6018   }
   6019 }
   6020 
   6021 void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
   6022                                                           Location root,
   6023                                                           Register obj,
   6024                                                           uint32_t offset) {
   6025   Register root_reg = root.AsRegister<Register>();
   6026   if (kEmitCompilerReadBarrier) {
   6027     if (kUseBakerReadBarrier) {
   6028       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
   6029       // Baker's read barrier are used:
   6030       //
   6031       //   root = obj.field;
   6032       //   if (Thread::Current()->GetIsGcMarking()) {
   6033       //     root = ReadBarrier::Mark(root)
   6034       //   }
   6035 
   6036       // /* GcRoot<mirror::Object> */ root = *(obj + offset)
   6037       __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
   6038       static_assert(
   6039           sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
   6040           "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
   6041           "have different sizes.");
   6042       static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
   6043                     "art::mirror::CompressedReference<mirror::Object> and int32_t "
   6044                     "have different sizes.");
   6045 
   6046       // Slow path used to mark the GC root `root`.
   6047       SlowPathCode* slow_path =
   6048           new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
   6049       codegen_->AddSlowPath(slow_path);
   6050 
   6051       // IP = Thread::Current()->GetIsGcMarking()
   6052       __ LoadFromOffset(
   6053           kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
   6054       __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
   6055       __ Bind(slow_path->GetExitLabel());
   6056     } else {
   6057       // GC root loaded through a slow path for read barriers other
   6058       // than Baker's.
   6059       // /* GcRoot<mirror::Object>* */ root = obj + offset
   6060       __ AddConstant(root_reg, obj, offset);
   6061       // /* mirror::Object* */ root = root->Read()
   6062       codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
   6063     }
   6064   } else {
   6065     // Plain GC root load with no read barrier.
   6066     // /* GcRoot<mirror::Object> */ root = *(obj + offset)
   6067     __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
   6068     // Note that GC roots are not affected by heap poisoning, thus we
   6069     // do not have to unpoison `root_reg` here.
   6070   }
   6071 }
   6072 
   6073 void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
   6074                                                              Location ref,
   6075                                                              Register obj,
   6076                                                              uint32_t offset,
   6077                                                              Location temp,
   6078                                                              bool needs_null_check) {
   6079   DCHECK(kEmitCompilerReadBarrier);
   6080   DCHECK(kUseBakerReadBarrier);
   6081 
   6082   // /* HeapReference<Object> */ ref = *(obj + offset)
   6083   Location no_index = Location::NoLocation();
   6084   GenerateReferenceLoadWithBakerReadBarrier(
   6085       instruction, ref, obj, offset, no_index, temp, needs_null_check);
   6086 }
   6087 
   6088 void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
   6089                                                              Location ref,
   6090                                                              Register obj,
   6091                                                              uint32_t data_offset,
   6092                                                              Location index,
   6093                                                              Location temp,
   6094                                                              bool needs_null_check) {
   6095   DCHECK(kEmitCompilerReadBarrier);
   6096   DCHECK(kUseBakerReadBarrier);
   6097 
   6098   // /* HeapReference<Object> */ ref =
   6099   //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
   6100   GenerateReferenceLoadWithBakerReadBarrier(
   6101       instruction, ref, obj, data_offset, index, temp, needs_null_check);
   6102 }
   6103 
   6104 void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
   6105                                                                  Location ref,
   6106                                                                  Register obj,
   6107                                                                  uint32_t offset,
   6108                                                                  Location index,
   6109                                                                  Location temp,
   6110                                                                  bool needs_null_check) {
   6111   DCHECK(kEmitCompilerReadBarrier);
   6112   DCHECK(kUseBakerReadBarrier);
   6113 
   6114   // In slow path based read barriers, the read barrier call is
   6115   // inserted after the original load. However, in fast path based
   6116   // Baker's read barriers, we need to perform the load of
   6117   // mirror::Object::monitor_ *before* the original reference load.
   6118   // This load-load ordering is required by the read barrier.
   6119   // The fast path/slow path (for Baker's algorithm) should look like:
   6120   //
   6121   //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
   6122   //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
   6123   //   HeapReference<Object> ref = *src;  // Original reference load.
   6124   //   bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
   6125   //   if (is_gray) {
   6126   //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
   6127   //   }
   6128   //
   6129   // Note: the original implementation in ReadBarrier::Barrier is
   6130   // slightly more complex as it performs additional checks that we do
   6131   // not do here for performance reasons.
   6132 
   6133   Register ref_reg = ref.AsRegister<Register>();
   6134   Register temp_reg = temp.AsRegister<Register>();
   6135   uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
   6136 
   6137   // /* int32_t */ monitor = obj->monitor_
   6138   __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
   6139   if (needs_null_check) {
   6140     MaybeRecordImplicitNullCheck(instruction);
   6141   }
   6142   // /* LockWord */ lock_word = LockWord(monitor)
   6143   static_assert(sizeof(LockWord) == sizeof(int32_t),
   6144                 "art::LockWord and int32_t have different sizes.");
   6145   // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
   6146   __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
   6147   __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
   6148   static_assert(
   6149       LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
   6150       "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
   6151 
   6152   // Introduce a dependency on the high bits of rb_state, which shall
   6153   // be all zeroes, to prevent load-load reordering, and without using
   6154   // a memory barrier (which would be more expensive).
   6155   // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
   6156   __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
   6157   // obj is unchanged by this operation, but its value now depends on
   6158   // IP, which depends on temp_reg.
   6159   __ add(obj, obj, ShifterOperand(IP));
   6160 
   6161   // The actual reference load.
   6162   if (index.IsValid()) {
   6163     static_assert(
   6164         sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
   6165         "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
   6166     // /* HeapReference<Object> */ ref =
   6167     //     *(obj + offset + index * sizeof(HeapReference<Object>))
   6168     if (index.IsConstant()) {
   6169       size_t computed_offset =
   6170           (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
   6171       __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
   6172     } else {
   6173       __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
   6174       __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
   6175     }
   6176   } else {
   6177     // /* HeapReference<Object> */ ref = *(obj + offset)
   6178     __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
   6179   }
   6180 
   6181   // Object* ref = ref_addr->AsMirrorPtr()
   6182   __ MaybeUnpoisonHeapReference(ref_reg);
   6183 
   6184   // Slow path used to mark the object `ref` when it is gray.
   6185   SlowPathCode* slow_path =
   6186       new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
   6187   AddSlowPath(slow_path);
   6188 
   6189   // if (rb_state == ReadBarrier::gray_ptr_)
   6190   //   ref = ReadBarrier::Mark(ref);
   6191   __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
   6192   __ b(slow_path->GetEntryLabel(), EQ);
   6193   __ Bind(slow_path->GetExitLabel());
   6194 }
   6195 
   6196 void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
   6197                                                Location out,
   6198                                                Location ref,
   6199                                                Location obj,
   6200                                                uint32_t offset,
   6201                                                Location index) {
   6202   DCHECK(kEmitCompilerReadBarrier);
   6203 
   6204   // Insert a slow path based read barrier *after* the reference load.
   6205   //
   6206   // If heap poisoning is enabled, the unpoisoning of the loaded
   6207   // reference will be carried out by the runtime within the slow
   6208   // path.
   6209   //
   6210   // Note that `ref` currently does not get unpoisoned (when heap
   6211   // poisoning is enabled), which is alright as the `ref` argument is
   6212   // not used by the artReadBarrierSlow entry point.
   6213   //
   6214   // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
   6215   SlowPathCode* slow_path = new (GetGraph()->GetArena())
   6216       ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
   6217   AddSlowPath(slow_path);
   6218 
   6219   __ b(slow_path->GetEntryLabel());
   6220   __ Bind(slow_path->GetExitLabel());
   6221 }
   6222 
   6223 void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
   6224                                                     Location out,
   6225                                                     Location ref,
   6226                                                     Location obj,
   6227                                                     uint32_t offset,
   6228                                                     Location index) {
   6229   if (kEmitCompilerReadBarrier) {
   6230     // Baker's read barriers shall be handled by the fast path
   6231     // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
   6232     DCHECK(!kUseBakerReadBarrier);
   6233     // If heap poisoning is enabled, unpoisoning will be taken care of
   6234     // by the runtime within the slow path.
   6235     GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
   6236   } else if (kPoisonHeapReferences) {
   6237     __ UnpoisonHeapReference(out.AsRegister<Register>());
   6238   }
   6239 }
   6240 
   6241 void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
   6242                                                       Location out,
   6243                                                       Location root) {
   6244   DCHECK(kEmitCompilerReadBarrier);
   6245 
   6246   // Insert a slow path based read barrier *after* the GC root load.
   6247   //
   6248   // Note that GC roots are not affected by heap poisoning, so we do
   6249   // not need to do anything special for this here.
   6250   SlowPathCode* slow_path =
   6251       new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
   6252   AddSlowPath(slow_path);
   6253 
   6254   __ b(slow_path->GetEntryLabel());
   6255   __ Bind(slow_path->GetExitLabel());
   6256 }
   6257 
   6258 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
   6259       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
   6260       MethodReference target_method) {
   6261   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
   6262   // We disable pc-relative load when there is an irreducible loop, as the optimization
   6263   // is incompatible with it.
   6264   // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
   6265   // with irreducible loops.
   6266   if (GetGraph()->HasIrreducibleLoops() &&
   6267       (dispatch_info.method_load_kind ==
   6268           HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
   6269     dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
   6270   }
   6271 
   6272   if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
   6273     const DexFile& outer_dex_file = GetGraph()->GetDexFile();
   6274     if (&outer_dex_file != target_method.dex_file) {
   6275       // Calls across dex files are more likely to exceed the available BL range,
   6276       // so use absolute patch with fixup if available and kCallArtMethod otherwise.
   6277       HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
   6278           (desired_dispatch_info.method_load_kind ==
   6279            HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
   6280           ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
   6281           : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
   6282       return HInvokeStaticOrDirect::DispatchInfo {
   6283         dispatch_info.method_load_kind,
   6284         code_ptr_location,
   6285         dispatch_info.method_load_data,
   6286         0u
   6287       };
   6288     }
   6289   }
   6290   return dispatch_info;
   6291 }
   6292 
   6293 Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
   6294                                                                  Register temp) {
   6295   DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
   6296   Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6297   if (!invoke->GetLocations()->Intrinsified()) {
   6298     return location.AsRegister<Register>();
   6299   }
   6300   // For intrinsics we allow any location, so it may be on the stack.
   6301   if (!location.IsRegister()) {
   6302     __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
   6303     return temp;
   6304   }
   6305   // For register locations, check if the register was saved. If so, get it from the stack.
   6306   // Note: There is a chance that the register was saved but not overwritten, so we could
   6307   // save one load. However, since this is just an intrinsic slow path we prefer this
   6308   // simple and more robust approach rather that trying to determine if that's the case.
   6309   SlowPathCode* slow_path = GetCurrentSlowPath();
   6310   DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
   6311   if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
   6312     int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
   6313     __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
   6314     return temp;
   6315   }
   6316   return location.AsRegister<Register>();
   6317 }
   6318 
   6319 void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
   6320   // For better instruction scheduling we load the direct code pointer before the method pointer.
   6321   switch (invoke->GetCodePtrLocation()) {
   6322     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
   6323       // LR = code address from literal pool with link-time patch.
   6324       __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
   6325       break;
   6326     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
   6327       // LR = invoke->GetDirectCodePtr();
   6328       __ LoadImmediate(LR, invoke->GetDirectCodePtr());
   6329       break;
   6330     default:
   6331       break;
   6332   }
   6333 
   6334   Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
   6335   switch (invoke->GetMethodLoadKind()) {
   6336     case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
   6337       // temp = thread->string_init_entrypoint
   6338       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
   6339       break;
   6340     case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
   6341       callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6342       break;
   6343     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
   6344       __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
   6345       break;
   6346     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
   6347       __ LoadLiteral(temp.AsRegister<Register>(),
   6348                      DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
   6349       break;
   6350     case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
   6351       HArmDexCacheArraysBase* base =
   6352           invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
   6353       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
   6354                                                                 temp.AsRegister<Register>());
   6355       int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
   6356       __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
   6357       break;
   6358     }
   6359     case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
   6360       Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
   6361       Register method_reg;
   6362       Register reg = temp.AsRegister<Register>();
   6363       if (current_method.IsRegister()) {
   6364         method_reg = current_method.AsRegister<Register>();
   6365       } else {
   6366         DCHECK(invoke->GetLocations()->Intrinsified());
   6367         DCHECK(!current_method.IsValid());
   6368         method_reg = reg;
   6369         __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
   6370       }
   6371       // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
   6372       __ LoadFromOffset(kLoadWord,
   6373                         reg,
   6374                         method_reg,
   6375                         ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
   6376       // temp = temp[index_in_cache];
   6377       // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
   6378       uint32_t index_in_cache = invoke->GetDexMethodIndex();
   6379       __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
   6380       break;
   6381     }
   6382   }
   6383 
   6384   switch (invoke->GetCodePtrLocation()) {
   6385     case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
   6386       __ bl(GetFrameEntryLabel());
   6387       break;
   6388     case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
   6389       relative_call_patches_.emplace_back(invoke->GetTargetMethod());
   6390       __ BindTrackedLabel(&relative_call_patches_.back().label);
   6391       // Arbitrarily branch to the BL itself, override at link time.
   6392       __ bl(&relative_call_patches_.back().label);
   6393       break;
   6394     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
   6395     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
   6396       // LR prepared above for better instruction scheduling.
   6397       // LR()
   6398       __ blx(LR);
   6399       break;
   6400     case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
   6401       // LR = callee_method->entry_point_from_quick_compiled_code_
   6402       __ LoadFromOffset(
   6403           kLoadWord, LR, callee_method.AsRegister<Register>(),
   6404           ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
   6405       // LR()
   6406       __ blx(LR);
   6407       break;
   6408   }
   6409 
   6410   DCHECK(!IsLeafMethod());
   6411 }
   6412 
   6413 void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
   6414   Register temp = temp_location.AsRegister<Register>();
   6415   uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
   6416       invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
   6417 
   6418   // Use the calling convention instead of the location of the receiver, as
   6419   // intrinsics may have put the receiver in a different register. In the intrinsics
   6420   // slow path, the arguments have been moved to the right place, so here we are
   6421   // guaranteed that the receiver is the first register of the calling convention.
   6422   InvokeDexCallingConvention calling_convention;
   6423   Register receiver = calling_convention.GetRegisterAt(0);
   6424   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   6425   // /* HeapReference<Class> */ temp = receiver->klass_
   6426   __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
   6427   MaybeRecordImplicitNullCheck(invoke);
   6428   // Instead of simply (possibly) unpoisoning `temp` here, we should
   6429   // emit a read barrier for the previous class reference load.
   6430   // However this is not required in practice, as this is an
   6431   // intermediate/temporary reference and because the current
   6432   // concurrent copying collector keeps the from-space memory
   6433   // intact/accessible until the end of the marking phase (the
   6434   // concurrent copying collector may not in the future).
   6435   __ MaybeUnpoisonHeapReference(temp);
   6436   // temp = temp->GetMethodAt(method_offset);
   6437   uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
   6438       kArmWordSize).Int32Value();
   6439   __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
   6440   // LR = temp->GetEntryPoint();
   6441   __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
   6442   // LR();
   6443   __ blx(LR);
   6444 }
   6445 
   6446 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
   6447     const DexFile& dex_file, uint32_t string_index) {
   6448   return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
   6449 }
   6450 
   6451 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
   6452     const DexFile& dex_file, uint32_t element_offset) {
   6453   return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
   6454 }
   6455 
   6456 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
   6457     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   6458   patches->emplace_back(dex_file, offset_or_index);
   6459   return &patches->back();
   6460 }
   6461 
   6462 Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
   6463                                                              uint32_t string_index) {
   6464   return boot_image_string_patches_.GetOrCreate(
   6465       StringReference(&dex_file, string_index),
   6466       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
   6467 }
   6468 
   6469 Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
   6470   bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
   6471   Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
   6472   return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
   6473 }
   6474 
   6475 Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
   6476   return DeduplicateUint32Literal(address, &uint32_literals_);
   6477 }
   6478 
   6479 void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   6480   DCHECK(linker_patches->empty());
   6481   size_t size =
   6482       method_patches_.size() +
   6483       call_patches_.size() +
   6484       relative_call_patches_.size() +
   6485       /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
   6486       boot_image_string_patches_.size() +
   6487       /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
   6488       boot_image_address_patches_.size();
   6489   linker_patches->reserve(size);
   6490   for (const auto& entry : method_patches_) {
   6491     const MethodReference& target_method = entry.first;
   6492     Literal* literal = entry.second;
   6493     DCHECK(literal->GetLabel()->IsBound());
   6494     uint32_t literal_offset = literal->GetLabel()->Position();
   6495     linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
   6496                                                        target_method.dex_file,
   6497                                                        target_method.dex_method_index));
   6498   }
   6499   for (const auto& entry : call_patches_) {
   6500     const MethodReference& target_method = entry.first;
   6501     Literal* literal = entry.second;
   6502     DCHECK(literal->GetLabel()->IsBound());
   6503     uint32_t literal_offset = literal->GetLabel()->Position();
   6504     linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
   6505                                                      target_method.dex_file,
   6506                                                      target_method.dex_method_index));
   6507   }
   6508   for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
   6509     uint32_t literal_offset = info.label.Position();
   6510     linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
   6511                                                              info.target_method.dex_file,
   6512                                                              info.target_method.dex_method_index));
   6513   }
   6514   for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
   6515     const DexFile& dex_file = info.target_dex_file;
   6516     size_t base_element_offset = info.offset_or_index;
   6517     DCHECK(info.add_pc_label.IsBound());
   6518     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
   6519     // Add MOVW patch.
   6520     DCHECK(info.movw_label.IsBound());
   6521     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
   6522     linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
   6523                                                               &dex_file,
   6524                                                               add_pc_offset,
   6525                                                               base_element_offset));
   6526     // Add MOVT patch.
   6527     DCHECK(info.movt_label.IsBound());
   6528     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
   6529     linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
   6530                                                               &dex_file,
   6531                                                               add_pc_offset,
   6532                                                               base_element_offset));
   6533   }
   6534   for (const auto& entry : boot_image_string_patches_) {
   6535     const StringReference& target_string = entry.first;
   6536     Literal* literal = entry.second;
   6537     DCHECK(literal->GetLabel()->IsBound());
   6538     uint32_t literal_offset = literal->GetLabel()->Position();
   6539     linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
   6540                                                        target_string.dex_file,
   6541                                                        target_string.string_index));
   6542   }
   6543   for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
   6544     const DexFile& dex_file = info.target_dex_file;
   6545     uint32_t string_index = info.offset_or_index;
   6546     DCHECK(info.add_pc_label.IsBound());
   6547     uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
   6548     // Add MOVW patch.
   6549     DCHECK(info.movw_label.IsBound());
   6550     uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
   6551     linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
   6552                                                                &dex_file,
   6553                                                                add_pc_offset,
   6554                                                                string_index));
   6555     // Add MOVT patch.
   6556     DCHECK(info.movt_label.IsBound());
   6557     uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
   6558     linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
   6559                                                                &dex_file,
   6560                                                                add_pc_offset,
   6561                                                                string_index));
   6562   }
   6563   for (const auto& entry : boot_image_address_patches_) {
   6564     DCHECK(GetCompilerOptions().GetIncludePatchInformation());
   6565     Literal* literal = entry.second;
   6566     DCHECK(literal->GetLabel()->IsBound());
   6567     uint32_t literal_offset = literal->GetLabel()->Position();
   6568     linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
   6569   }
   6570 }
   6571 
   6572 Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
   6573   return map->GetOrCreate(
   6574       value,
   6575       [this, value]() { return __ NewLiteral<uint32_t>(value); });
   6576 }
   6577 
   6578 Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
   6579                                                     MethodToLiteralMap* map) {
   6580   return map->GetOrCreate(
   6581       target_method,
   6582       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
   6583 }
   6584 
   6585 Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
   6586   return DeduplicateMethodLiteral(target_method, &method_patches_);
   6587 }
   6588 
   6589 Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
   6590   return DeduplicateMethodLiteral(target_method, &call_patches_);
   6591 }
   6592 
   6593 void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
   6594   LocationSummary* locations =
   6595       new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
   6596   locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
   6597                      Location::RequiresRegister());
   6598   locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
   6599   locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
   6600   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   6601 }
   6602 
   6603 void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
   6604   LocationSummary* locations = instr->GetLocations();
   6605   Register res = locations->Out().AsRegister<Register>();
   6606   Register accumulator =
   6607       locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
   6608   Register mul_left =
   6609       locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
   6610   Register mul_right =
   6611       locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
   6612 
   6613   if (instr->GetOpKind() == HInstruction::kAdd) {
   6614     __ mla(res, mul_left, mul_right, accumulator);
   6615   } else {
   6616     __ mls(res, mul_left, mul_right, accumulator);
   6617   }
   6618 }
   6619 
   6620 void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
   6621   // Nothing to do, this should be removed during prepare for register allocator.
   6622   LOG(FATAL) << "Unreachable";
   6623 }
   6624 
   6625 void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
   6626   // Nothing to do, this should be removed during prepare for register allocator.
   6627   LOG(FATAL) << "Unreachable";
   6628 }
   6629 
   6630 // Simple implementation of packed switch - generate cascaded compare/jumps.
   6631 void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
   6632   LocationSummary* locations =
   6633       new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
   6634   locations->SetInAt(0, Location::RequiresRegister());
   6635   if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
   6636       codegen_->GetAssembler()->IsThumb()) {
   6637     locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
   6638     if (switch_instr->GetStartValue() != 0) {
   6639       locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
   6640     }
   6641   }
   6642 }
   6643 
   6644 void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
   6645   int32_t lower_bound = switch_instr->GetStartValue();
   6646   uint32_t num_entries = switch_instr->GetNumEntries();
   6647   LocationSummary* locations = switch_instr->GetLocations();
   6648   Register value_reg = locations->InAt(0).AsRegister<Register>();
   6649   HBasicBlock* default_block = switch_instr->GetDefaultBlock();
   6650 
   6651   if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
   6652     // Create a series of compare/jumps.
   6653     Register temp_reg = IP;
   6654     // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
   6655     // the immediate, because IP is used as the destination register. For the other
   6656     // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
   6657     // and they can be encoded in the instruction without making use of IP register.
   6658     __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
   6659 
   6660     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
   6661     // Jump to successors[0] if value == lower_bound.
   6662     __ b(codegen_->GetLabelOf(successors[0]), EQ);
   6663     int32_t last_index = 0;
   6664     for (; num_entries - last_index > 2; last_index += 2) {
   6665       __ AddConstantSetFlags(temp_reg, temp_reg, -2);
   6666       // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
   6667       __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
   6668       // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
   6669       __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
   6670     }
   6671     if (num_entries - last_index == 2) {
   6672       // The last missing case_value.
   6673       __ CmpConstant(temp_reg, 1);
   6674       __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
   6675     }
   6676 
   6677     // And the default for any other value.
   6678     if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
   6679       __ b(codegen_->GetLabelOf(default_block));
   6680     }
   6681   } else {
   6682     // Create a table lookup.
   6683     Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
   6684 
   6685     // Materialize a pointer to the switch table
   6686     std::vector<Label*> labels(num_entries);
   6687     const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
   6688     for (uint32_t i = 0; i < num_entries; i++) {
   6689       labels[i] = codegen_->GetLabelOf(successors[i]);
   6690     }
   6691     JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
   6692 
   6693     // Remove the bias.
   6694     Register key_reg;
   6695     if (lower_bound != 0) {
   6696       key_reg = locations->GetTemp(1).AsRegister<Register>();
   6697       __ AddConstant(key_reg, value_reg, -lower_bound);
   6698     } else {
   6699       key_reg = value_reg;
   6700     }
   6701 
   6702     // Check whether the value is in the table, jump to default block if not.
   6703     __ CmpConstant(key_reg, num_entries - 1);
   6704     __ b(codegen_->GetLabelOf(default_block), Condition::HI);
   6705 
   6706     // Load the displacement from the table.
   6707     __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
   6708 
   6709     // Dispatch is a direct add to the PC (for Thumb2).
   6710     __ EmitJumpTableDispatch(table, temp_reg);
   6711   }
   6712 }
   6713 
   6714 void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
   6715   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
   6716   locations->SetOut(Location::RequiresRegister());
   6717 }
   6718 
   6719 void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
   6720   Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
   6721   CodeGeneratorARM::PcRelativePatchInfo* labels =
   6722       codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
   6723   __ BindTrackedLabel(&labels->movw_label);
   6724   __ movw(base_reg, /* placeholder */ 0u);
   6725   __ BindTrackedLabel(&labels->movt_label);
   6726   __ movt(base_reg, /* placeholder */ 0u);
   6727   __ BindTrackedLabel(&labels->add_pc_label);
   6728   __ add(base_reg, base_reg, ShifterOperand(PC));
   6729 }
   6730 
   6731 void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
   6732   if (!trg.IsValid()) {
   6733     DCHECK_EQ(type, Primitive::kPrimVoid);
   6734     return;
   6735   }
   6736 
   6737   DCHECK_NE(type, Primitive::kPrimVoid);
   6738 
   6739   Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
   6740   if (return_loc.Equals(trg)) {
   6741     return;
   6742   }
   6743 
   6744   // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
   6745   //       with the last branch.
   6746   if (type == Primitive::kPrimLong) {
   6747     HParallelMove parallel_move(GetGraph()->GetArena());
   6748     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
   6749     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
   6750     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6751   } else if (type == Primitive::kPrimDouble) {
   6752     HParallelMove parallel_move(GetGraph()->GetArena());
   6753     parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
   6754     parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
   6755     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6756   } else {
   6757     // Let the parallel move resolver take care of all of this.
   6758     HParallelMove parallel_move(GetGraph()->GetArena());
   6759     parallel_move.AddMove(return_loc, trg, type, nullptr);
   6760     GetMoveResolver()->EmitNativeCode(&parallel_move);
   6761   }
   6762 }
   6763 
   6764 void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
   6765   LocationSummary* locations =
   6766       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   6767   locations->SetInAt(0, Location::RequiresRegister());
   6768   locations->SetOut(Location::RequiresRegister());
   6769 }
   6770 
   6771 void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
   6772   LocationSummary* locations = instruction->GetLocations();
   6773   uint32_t method_offset = 0;
   6774   if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
   6775     method_offset = mirror::Class::EmbeddedVTableEntryOffset(
   6776         instruction->GetIndex(), kArmPointerSize).SizeValue();
   6777   } else {
   6778     method_offset = mirror::Class::EmbeddedImTableEntryOffset(
   6779         instruction->GetIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
   6780   }
   6781   __ LoadFromOffset(kLoadWord,
   6782                     locations->Out().AsRegister<Register>(),
   6783                     locations->InAt(0).AsRegister<Register>(),
   6784                     method_offset);
   6785 }
   6786 
   6787 #undef __
   6788 #undef QUICK_ENTRY_POINT
   6789 
   6790 }  // namespace arm
   6791 }  // namespace art
   6792