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