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