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