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