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