code_generator_arm.cc revision 328429ff48d06e2cad4ebdd3568ab06de916a10a
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  HInstruction* array_instr = instruction->GetArray();
4441  bool has_intermediate_address = array_instr->IsIntermediateAddress();
4442  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4443  DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
4444
4445  switch (type) {
4446    case Primitive::kPrimBoolean:
4447    case Primitive::kPrimByte:
4448    case Primitive::kPrimShort:
4449    case Primitive::kPrimChar:
4450    case Primitive::kPrimInt: {
4451      if (index.IsConstant()) {
4452        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
4453        uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
4454
4455        LoadOperandType load_type = GetLoadOperandType(type);
4456        __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
4457      } else {
4458        Register temp = IP;
4459
4460        if (has_intermediate_address) {
4461          // We do not need to compute the intermediate address from the array: the
4462          // input instruction has done it already. See the comment in
4463          // `TryExtractArrayAccessAddress()`.
4464          if (kIsDebugBuild) {
4465            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4466            DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4467          }
4468          temp = obj;
4469        } else {
4470          __ add(temp, obj, ShifterOperand(data_offset));
4471        }
4472        codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
4473      }
4474      break;
4475    }
4476
4477    case Primitive::kPrimNot: {
4478      static_assert(
4479          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4480          "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4481      // /* HeapReference<Object> */ out =
4482      //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
4483      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4484        Location temp = locations->GetTemp(0);
4485        // Note that a potential implicit null check is handled in this
4486        // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4487        codegen_->GenerateArrayLoadWithBakerReadBarrier(
4488            instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4489      } else {
4490        Register out = out_loc.AsRegister<Register>();
4491        if (index.IsConstant()) {
4492          size_t offset =
4493              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4494          __ LoadFromOffset(kLoadWord, out, obj, offset);
4495          codegen_->MaybeRecordImplicitNullCheck(instruction);
4496          // If read barriers are enabled, emit read barriers other than
4497          // Baker's using a slow path (and also unpoison the loaded
4498          // reference, if heap poisoning is enabled).
4499          codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4500        } else {
4501          Register temp = IP;
4502
4503          if (has_intermediate_address) {
4504            // We do not need to compute the intermediate address from the array: the
4505            // input instruction has done it already. See the comment in
4506            // `TryExtractArrayAccessAddress()`.
4507            if (kIsDebugBuild) {
4508              HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4509              DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4510            }
4511            temp = obj;
4512          } else {
4513            __ add(temp, obj, ShifterOperand(data_offset));
4514          }
4515          codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
4516
4517          codegen_->MaybeRecordImplicitNullCheck(instruction);
4518          // If read barriers are enabled, emit read barriers other than
4519          // Baker's using a slow path (and also unpoison the loaded
4520          // reference, if heap poisoning is enabled).
4521          codegen_->MaybeGenerateReadBarrierSlow(
4522              instruction, out_loc, out_loc, obj_loc, data_offset, index);
4523        }
4524      }
4525      break;
4526    }
4527
4528    case Primitive::kPrimLong: {
4529      if (index.IsConstant()) {
4530        size_t offset =
4531            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4532        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
4533      } else {
4534        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4535        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
4536      }
4537      break;
4538    }
4539
4540    case Primitive::kPrimFloat: {
4541      SRegister out = out_loc.AsFpuRegister<SRegister>();
4542      if (index.IsConstant()) {
4543        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4544        __ LoadSFromOffset(out, obj, offset);
4545      } else {
4546        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4547        __ LoadSFromOffset(out, IP, data_offset);
4548      }
4549      break;
4550    }
4551
4552    case Primitive::kPrimDouble: {
4553      SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
4554      if (index.IsConstant()) {
4555        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4556        __ LoadDFromOffset(FromLowSToD(out), obj, offset);
4557      } else {
4558        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4559        __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
4560      }
4561      break;
4562    }
4563
4564    case Primitive::kPrimVoid:
4565      LOG(FATAL) << "Unreachable type " << type;
4566      UNREACHABLE();
4567  }
4568
4569  if (type == Primitive::kPrimNot) {
4570    // Potential implicit null checks, in the case of reference
4571    // arrays, are handled in the previous switch statement.
4572  } else {
4573    codegen_->MaybeRecordImplicitNullCheck(instruction);
4574  }
4575}
4576
4577void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
4578  Primitive::Type value_type = instruction->GetComponentType();
4579
4580  bool needs_write_barrier =
4581      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4582  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4583  bool object_array_set_with_read_barrier =
4584      kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
4585
4586  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4587      instruction,
4588      (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4589          LocationSummary::kCallOnSlowPath :
4590          LocationSummary::kNoCall);
4591
4592  locations->SetInAt(0, Location::RequiresRegister());
4593  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4594  if (Primitive::IsFloatingPointType(value_type)) {
4595    locations->SetInAt(2, Location::RequiresFpuRegister());
4596  } else {
4597    locations->SetInAt(2, Location::RequiresRegister());
4598  }
4599  if (needs_write_barrier) {
4600    // Temporary registers for the write barrier.
4601    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
4602    locations->AddTemp(Location::RequiresRegister());
4603  }
4604}
4605
4606void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4607  LocationSummary* locations = instruction->GetLocations();
4608  Location array_loc = locations->InAt(0);
4609  Register array = array_loc.AsRegister<Register>();
4610  Location index = locations->InAt(1);
4611  Primitive::Type value_type = instruction->GetComponentType();
4612  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4613  bool needs_write_barrier =
4614      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4615  uint32_t data_offset =
4616      mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
4617  Location value_loc = locations->InAt(2);
4618  HInstruction* array_instr = instruction->GetArray();
4619  bool has_intermediate_address = array_instr->IsIntermediateAddress();
4620  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4621  DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
4622
4623  switch (value_type) {
4624    case Primitive::kPrimBoolean:
4625    case Primitive::kPrimByte:
4626    case Primitive::kPrimShort:
4627    case Primitive::kPrimChar:
4628    case Primitive::kPrimInt: {
4629      if (index.IsConstant()) {
4630        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
4631        uint32_t full_offset =
4632            data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
4633        StoreOperandType store_type = GetStoreOperandType(value_type);
4634        __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
4635      } else {
4636        Register temp = IP;
4637
4638        if (has_intermediate_address) {
4639          // We do not need to compute the intermediate address from the array: the
4640          // input instruction has done it already. See the comment in
4641          // `TryExtractArrayAccessAddress()`.
4642          if (kIsDebugBuild) {
4643            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4644            DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
4645          }
4646          temp = array;
4647        } else {
4648          __ add(temp, array, ShifterOperand(data_offset));
4649        }
4650        codegen_->StoreToShiftedRegOffset(value_type,
4651                                          value_loc,
4652                                          temp,
4653                                          index.AsRegister<Register>());
4654      }
4655      break;
4656    }
4657
4658    case Primitive::kPrimNot: {
4659      Register value = value_loc.AsRegister<Register>();
4660      // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
4661      // See the comment in instruction_simplifier_shared.cc.
4662      DCHECK(!has_intermediate_address);
4663
4664      if (instruction->InputAt(2)->IsNullConstant()) {
4665        // Just setting null.
4666        if (index.IsConstant()) {
4667          size_t offset =
4668              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4669          __ StoreToOffset(kStoreWord, value, array, offset);
4670        } else {
4671          DCHECK(index.IsRegister()) << index;
4672          __ add(IP, array, ShifterOperand(data_offset));
4673          codegen_->StoreToShiftedRegOffset(value_type,
4674                                            value_loc,
4675                                            IP,
4676                                            index.AsRegister<Register>());
4677        }
4678        codegen_->MaybeRecordImplicitNullCheck(instruction);
4679        DCHECK(!needs_write_barrier);
4680        DCHECK(!may_need_runtime_call_for_type_check);
4681        break;
4682      }
4683
4684      DCHECK(needs_write_barrier);
4685      Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4686      Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4687      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4688      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4689      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4690      Label done;
4691      SlowPathCode* slow_path = nullptr;
4692
4693      if (may_need_runtime_call_for_type_check) {
4694        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4695        codegen_->AddSlowPath(slow_path);
4696        if (instruction->GetValueCanBeNull()) {
4697          Label non_zero;
4698          __ CompareAndBranchIfNonZero(value, &non_zero);
4699          if (index.IsConstant()) {
4700            size_t offset =
4701               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4702            __ StoreToOffset(kStoreWord, value, array, offset);
4703          } else {
4704            DCHECK(index.IsRegister()) << index;
4705            __ add(IP, array, ShifterOperand(data_offset));
4706            codegen_->StoreToShiftedRegOffset(value_type,
4707                                              value_loc,
4708                                              IP,
4709                                              index.AsRegister<Register>());
4710          }
4711          codegen_->MaybeRecordImplicitNullCheck(instruction);
4712          __ b(&done);
4713          __ Bind(&non_zero);
4714        }
4715
4716        if (kEmitCompilerReadBarrier) {
4717          // When read barriers are enabled, the type checking
4718          // instrumentation requires two read barriers:
4719          //
4720          //   __ Mov(temp2, temp1);
4721          //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
4722          //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4723          //   codegen_->GenerateReadBarrierSlow(
4724          //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4725          //
4726          //   // /* HeapReference<Class> */ temp2 = value->klass_
4727          //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4728          //   codegen_->GenerateReadBarrierSlow(
4729          //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4730          //
4731          //   __ cmp(temp1, ShifterOperand(temp2));
4732          //
4733          // However, the second read barrier may trash `temp`, as it
4734          // is a temporary register, and as such would not be saved
4735          // along with live registers before calling the runtime (nor
4736          // restored afterwards).  So in this case, we bail out and
4737          // delegate the work to the array set slow path.
4738          //
4739          // TODO: Extend the register allocator to support a new
4740          // "(locally) live temp" location so as to avoid always
4741          // going into the slow path when read barriers are enabled.
4742          __ b(slow_path->GetEntryLabel());
4743        } else {
4744          // /* HeapReference<Class> */ temp1 = array->klass_
4745          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4746          codegen_->MaybeRecordImplicitNullCheck(instruction);
4747          __ MaybeUnpoisonHeapReference(temp1);
4748
4749          // /* HeapReference<Class> */ temp1 = temp1->component_type_
4750          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4751          // /* HeapReference<Class> */ temp2 = value->klass_
4752          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4753          // If heap poisoning is enabled, no need to unpoison `temp1`
4754          // nor `temp2`, as we are comparing two poisoned references.
4755          __ cmp(temp1, ShifterOperand(temp2));
4756
4757          if (instruction->StaticTypeOfArrayIsObjectArray()) {
4758            Label do_put;
4759            __ b(&do_put, EQ);
4760            // If heap poisoning is enabled, the `temp1` reference has
4761            // not been unpoisoned yet; unpoison it now.
4762            __ MaybeUnpoisonHeapReference(temp1);
4763
4764            // /* HeapReference<Class> */ temp1 = temp1->super_class_
4765            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4766            // If heap poisoning is enabled, no need to unpoison
4767            // `temp1`, as we are comparing against null below.
4768            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4769            __ Bind(&do_put);
4770          } else {
4771            __ b(slow_path->GetEntryLabel(), NE);
4772          }
4773        }
4774      }
4775
4776      Register source = value;
4777      if (kPoisonHeapReferences) {
4778        // Note that in the case where `value` is a null reference,
4779        // we do not enter this block, as a null reference does not
4780        // need poisoning.
4781        DCHECK_EQ(value_type, Primitive::kPrimNot);
4782        __ Mov(temp1, value);
4783        __ PoisonHeapReference(temp1);
4784        source = temp1;
4785      }
4786
4787      if (index.IsConstant()) {
4788        size_t offset =
4789            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4790        __ StoreToOffset(kStoreWord, source, array, offset);
4791      } else {
4792        DCHECK(index.IsRegister()) << index;
4793
4794        __ add(IP, array, ShifterOperand(data_offset));
4795        codegen_->StoreToShiftedRegOffset(value_type,
4796                                          Location::RegisterLocation(source),
4797                                          IP,
4798                                          index.AsRegister<Register>());
4799      }
4800
4801      if (!may_need_runtime_call_for_type_check) {
4802        codegen_->MaybeRecordImplicitNullCheck(instruction);
4803      }
4804
4805      codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4806
4807      if (done.IsLinked()) {
4808        __ Bind(&done);
4809      }
4810
4811      if (slow_path != nullptr) {
4812        __ Bind(slow_path->GetExitLabel());
4813      }
4814
4815      break;
4816    }
4817
4818    case Primitive::kPrimLong: {
4819      Location value = locations->InAt(2);
4820      if (index.IsConstant()) {
4821        size_t offset =
4822            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4823        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
4824      } else {
4825        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4826        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
4827      }
4828      break;
4829    }
4830
4831    case Primitive::kPrimFloat: {
4832      Location value = locations->InAt(2);
4833      DCHECK(value.IsFpuRegister());
4834      if (index.IsConstant()) {
4835        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4836        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
4837      } else {
4838        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4839        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4840      }
4841      break;
4842    }
4843
4844    case Primitive::kPrimDouble: {
4845      Location value = locations->InAt(2);
4846      DCHECK(value.IsFpuRegisterPair());
4847      if (index.IsConstant()) {
4848        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4849        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
4850      } else {
4851        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4852        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4853      }
4854
4855      break;
4856    }
4857
4858    case Primitive::kPrimVoid:
4859      LOG(FATAL) << "Unreachable type " << value_type;
4860      UNREACHABLE();
4861  }
4862
4863  // Objects are handled in the switch.
4864  if (value_type != Primitive::kPrimNot) {
4865    codegen_->MaybeRecordImplicitNullCheck(instruction);
4866  }
4867}
4868
4869void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
4870  LocationSummary* locations =
4871      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4872  locations->SetInAt(0, Location::RequiresRegister());
4873  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4874}
4875
4876void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4877  LocationSummary* locations = instruction->GetLocations();
4878  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
4879  Register obj = locations->InAt(0).AsRegister<Register>();
4880  Register out = locations->Out().AsRegister<Register>();
4881  __ LoadFromOffset(kLoadWord, out, obj, offset);
4882  codegen_->MaybeRecordImplicitNullCheck(instruction);
4883}
4884
4885void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
4886  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4887  DCHECK(!kEmitCompilerReadBarrier);
4888  LocationSummary* locations =
4889      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4890
4891  locations->SetInAt(0, Location::RequiresRegister());
4892  locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
4893  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4894}
4895
4896void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
4897  LocationSummary* locations = instruction->GetLocations();
4898  Location out = locations->Out();
4899  Location first = locations->InAt(0);
4900  Location second = locations->InAt(1);
4901
4902  // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4903  DCHECK(!kEmitCompilerReadBarrier);
4904
4905  if (second.IsRegister()) {
4906    __ add(out.AsRegister<Register>(),
4907           first.AsRegister<Register>(),
4908           ShifterOperand(second.AsRegister<Register>()));
4909  } else {
4910    __ AddConstant(out.AsRegister<Register>(),
4911                   first.AsRegister<Register>(),
4912                   second.GetConstant()->AsIntConstant()->GetValue());
4913  }
4914}
4915
4916void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4917  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4918      ? LocationSummary::kCallOnSlowPath
4919      : LocationSummary::kNoCall;
4920  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4921  locations->SetInAt(0, Location::RequiresRegister());
4922  locations->SetInAt(1, Location::RequiresRegister());
4923  if (instruction->HasUses()) {
4924    locations->SetOut(Location::SameAsFirstInput());
4925  }
4926}
4927
4928void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4929  LocationSummary* locations = instruction->GetLocations();
4930  SlowPathCode* slow_path =
4931      new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
4932  codegen_->AddSlowPath(slow_path);
4933
4934  Register index = locations->InAt(0).AsRegister<Register>();
4935  Register length = locations->InAt(1).AsRegister<Register>();
4936
4937  __ cmp(index, ShifterOperand(length));
4938  __ b(slow_path->GetEntryLabel(), HS);
4939}
4940
4941void CodeGeneratorARM::MarkGCCard(Register temp,
4942                                  Register card,
4943                                  Register object,
4944                                  Register value,
4945                                  bool can_be_null) {
4946  Label is_null;
4947  if (can_be_null) {
4948    __ CompareAndBranchIfZero(value, &is_null);
4949  }
4950  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4951  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4952  __ strb(card, Address(card, temp));
4953  if (can_be_null) {
4954    __ Bind(&is_null);
4955  }
4956}
4957
4958void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
4959  LOG(FATAL) << "Unreachable";
4960}
4961
4962void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
4963  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4964}
4965
4966void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4967  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4968}
4969
4970void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4971  HBasicBlock* block = instruction->GetBlock();
4972  if (block->GetLoopInformation() != nullptr) {
4973    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4974    // The back edge will generate the suspend check.
4975    return;
4976  }
4977  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4978    // The goto will generate the suspend check.
4979    return;
4980  }
4981  GenerateSuspendCheck(instruction, nullptr);
4982}
4983
4984void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4985                                                       HBasicBlock* successor) {
4986  SuspendCheckSlowPathARM* slow_path =
4987      down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4988  if (slow_path == nullptr) {
4989    slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4990    instruction->SetSlowPath(slow_path);
4991    codegen_->AddSlowPath(slow_path);
4992    if (successor != nullptr) {
4993      DCHECK(successor->IsLoopHeader());
4994      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4995    }
4996  } else {
4997    DCHECK_EQ(slow_path->GetSuccessor(), successor);
4998  }
4999
5000  __ LoadFromOffset(
5001      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
5002  if (successor == nullptr) {
5003    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
5004    __ Bind(slow_path->GetReturnLabel());
5005  } else {
5006    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
5007    __ b(slow_path->GetEntryLabel());
5008  }
5009}
5010
5011ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
5012  return codegen_->GetAssembler();
5013}
5014
5015void ParallelMoveResolverARM::EmitMove(size_t index) {
5016  MoveOperands* move = moves_[index];
5017  Location source = move->GetSource();
5018  Location destination = move->GetDestination();
5019
5020  if (source.IsRegister()) {
5021    if (destination.IsRegister()) {
5022      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
5023    } else if (destination.IsFpuRegister()) {
5024      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
5025    } else {
5026      DCHECK(destination.IsStackSlot());
5027      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
5028                       SP, destination.GetStackIndex());
5029    }
5030  } else if (source.IsStackSlot()) {
5031    if (destination.IsRegister()) {
5032      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
5033                        SP, source.GetStackIndex());
5034    } else if (destination.IsFpuRegister()) {
5035      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
5036    } else {
5037      DCHECK(destination.IsStackSlot());
5038      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
5039      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5040    }
5041  } else if (source.IsFpuRegister()) {
5042    if (destination.IsRegister()) {
5043      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
5044    } else if (destination.IsFpuRegister()) {
5045      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
5046    } else {
5047      DCHECK(destination.IsStackSlot());
5048      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
5049    }
5050  } else if (source.IsDoubleStackSlot()) {
5051    if (destination.IsDoubleStackSlot()) {
5052      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
5053      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
5054    } else if (destination.IsRegisterPair()) {
5055      DCHECK(ExpectedPairLayout(destination));
5056      __ LoadFromOffset(
5057          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
5058    } else {
5059      DCHECK(destination.IsFpuRegisterPair()) << destination;
5060      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5061                         SP,
5062                         source.GetStackIndex());
5063    }
5064  } else if (source.IsRegisterPair()) {
5065    if (destination.IsRegisterPair()) {
5066      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
5067      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
5068    } else if (destination.IsFpuRegisterPair()) {
5069      __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5070                 source.AsRegisterPairLow<Register>(),
5071                 source.AsRegisterPairHigh<Register>());
5072    } else {
5073      DCHECK(destination.IsDoubleStackSlot()) << destination;
5074      DCHECK(ExpectedPairLayout(source));
5075      __ StoreToOffset(
5076          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
5077    }
5078  } else if (source.IsFpuRegisterPair()) {
5079    if (destination.IsRegisterPair()) {
5080      __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5081                 destination.AsRegisterPairHigh<Register>(),
5082                 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5083    } else if (destination.IsFpuRegisterPair()) {
5084      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5085               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5086    } else {
5087      DCHECK(destination.IsDoubleStackSlot()) << destination;
5088      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
5089                        SP,
5090                        destination.GetStackIndex());
5091    }
5092  } else {
5093    DCHECK(source.IsConstant()) << source;
5094    HConstant* constant = source.GetConstant();
5095    if (constant->IsIntConstant() || constant->IsNullConstant()) {
5096      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
5097      if (destination.IsRegister()) {
5098        __ LoadImmediate(destination.AsRegister<Register>(), value);
5099      } else {
5100        DCHECK(destination.IsStackSlot());
5101        __ LoadImmediate(IP, value);
5102        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5103      }
5104    } else if (constant->IsLongConstant()) {
5105      int64_t value = constant->AsLongConstant()->GetValue();
5106      if (destination.IsRegisterPair()) {
5107        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5108        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
5109      } else {
5110        DCHECK(destination.IsDoubleStackSlot()) << destination;
5111        __ LoadImmediate(IP, Low32Bits(value));
5112        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5113        __ LoadImmediate(IP, High32Bits(value));
5114        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5115      }
5116    } else if (constant->IsDoubleConstant()) {
5117      double value = constant->AsDoubleConstant()->GetValue();
5118      if (destination.IsFpuRegisterPair()) {
5119        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
5120      } else {
5121        DCHECK(destination.IsDoubleStackSlot()) << destination;
5122        uint64_t int_value = bit_cast<uint64_t, double>(value);
5123        __ LoadImmediate(IP, Low32Bits(int_value));
5124        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5125        __ LoadImmediate(IP, High32Bits(int_value));
5126        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5127      }
5128    } else {
5129      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
5130      float value = constant->AsFloatConstant()->GetValue();
5131      if (destination.IsFpuRegister()) {
5132        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5133      } else {
5134        DCHECK(destination.IsStackSlot());
5135        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5136        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5137      }
5138    }
5139  }
5140}
5141
5142void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5143  __ Mov(IP, reg);
5144  __ LoadFromOffset(kLoadWord, reg, SP, mem);
5145  __ StoreToOffset(kStoreWord, IP, SP, mem);
5146}
5147
5148void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5149  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5150  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5151  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5152                    SP, mem1 + stack_offset);
5153  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5154  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5155                   SP, mem2 + stack_offset);
5156  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5157}
5158
5159void ParallelMoveResolverARM::EmitSwap(size_t index) {
5160  MoveOperands* move = moves_[index];
5161  Location source = move->GetSource();
5162  Location destination = move->GetDestination();
5163
5164  if (source.IsRegister() && destination.IsRegister()) {
5165    DCHECK_NE(source.AsRegister<Register>(), IP);
5166    DCHECK_NE(destination.AsRegister<Register>(), IP);
5167    __ Mov(IP, source.AsRegister<Register>());
5168    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5169    __ Mov(destination.AsRegister<Register>(), IP);
5170  } else if (source.IsRegister() && destination.IsStackSlot()) {
5171    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
5172  } else if (source.IsStackSlot() && destination.IsRegister()) {
5173    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
5174  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5175    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5176  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5177    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
5178    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
5179    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
5180  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
5181    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
5182    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
5183    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
5184    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5185               destination.AsRegisterPairHigh<Register>(),
5186               DTMP);
5187  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
5188    Register low_reg = source.IsRegisterPair()
5189        ? source.AsRegisterPairLow<Register>()
5190        : destination.AsRegisterPairLow<Register>();
5191    int mem = source.IsRegisterPair()
5192        ? destination.GetStackIndex()
5193        : source.GetStackIndex();
5194    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
5195    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
5196    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
5197    __ StoreDToOffset(DTMP, SP, mem);
5198  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
5199    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5200    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5201    __ vmovd(DTMP, first);
5202    __ vmovd(first, second);
5203    __ vmovd(second, DTMP);
5204  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5205    DRegister reg = source.IsFpuRegisterPair()
5206        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5207        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5208    int mem = source.IsFpuRegisterPair()
5209        ? destination.GetStackIndex()
5210        : source.GetStackIndex();
5211    __ vmovd(DTMP, reg);
5212    __ LoadDFromOffset(reg, SP, mem);
5213    __ StoreDToOffset(DTMP, SP, mem);
5214  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5215    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5216                                           : destination.AsFpuRegister<SRegister>();
5217    int mem = source.IsFpuRegister()
5218        ? destination.GetStackIndex()
5219        : source.GetStackIndex();
5220
5221    __ vmovrs(IP, reg);
5222    __ LoadSFromOffset(reg, SP, mem);
5223    __ StoreToOffset(kStoreWord, IP, SP, mem);
5224  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5225    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5226    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
5227  } else {
5228    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
5229  }
5230}
5231
5232void ParallelMoveResolverARM::SpillScratch(int reg) {
5233  __ Push(static_cast<Register>(reg));
5234}
5235
5236void ParallelMoveResolverARM::RestoreScratch(int reg) {
5237  __ Pop(static_cast<Register>(reg));
5238}
5239
5240HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5241    HLoadClass::LoadKind desired_class_load_kind) {
5242  if (kEmitCompilerReadBarrier) {
5243    switch (desired_class_load_kind) {
5244      case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5245      case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5246      case HLoadClass::LoadKind::kBootImageAddress:
5247        // TODO: Implement for read barrier.
5248        return HLoadClass::LoadKind::kDexCacheViaMethod;
5249      default:
5250        break;
5251    }
5252  }
5253  switch (desired_class_load_kind) {
5254    case HLoadClass::LoadKind::kReferrersClass:
5255      break;
5256    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5257      DCHECK(!GetCompilerOptions().GetCompilePic());
5258      break;
5259    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5260      DCHECK(GetCompilerOptions().GetCompilePic());
5261      break;
5262    case HLoadClass::LoadKind::kBootImageAddress:
5263      break;
5264    case HLoadClass::LoadKind::kDexCacheAddress:
5265      DCHECK(Runtime::Current()->UseJitCompilation());
5266      break;
5267    case HLoadClass::LoadKind::kDexCachePcRelative:
5268      DCHECK(!Runtime::Current()->UseJitCompilation());
5269      // We disable pc-relative load when there is an irreducible loop, as the optimization
5270      // is incompatible with it.
5271      // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5272      // with irreducible loops.
5273      if (GetGraph()->HasIrreducibleLoops()) {
5274        return HLoadClass::LoadKind::kDexCacheViaMethod;
5275      }
5276      break;
5277    case HLoadClass::LoadKind::kDexCacheViaMethod:
5278      break;
5279  }
5280  return desired_class_load_kind;
5281}
5282
5283void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
5284  if (cls->NeedsAccessCheck()) {
5285    InvokeRuntimeCallingConvention calling_convention;
5286    CodeGenerator::CreateLoadClassLocationSummary(
5287        cls,
5288        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5289        Location::RegisterLocation(R0),
5290        /* code_generator_supports_read_barrier */ true);
5291    return;
5292  }
5293
5294  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
5295      ? LocationSummary::kCallOnSlowPath
5296      : LocationSummary::kNoCall;
5297  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
5298  HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5299  if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
5300      load_kind == HLoadClass::LoadKind::kDexCacheViaMethod ||
5301      load_kind == HLoadClass::LoadKind::kDexCachePcRelative) {
5302    locations->SetInAt(0, Location::RequiresRegister());
5303  }
5304  locations->SetOut(Location::RequiresRegister());
5305}
5306
5307void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
5308  LocationSummary* locations = cls->GetLocations();
5309  if (cls->NeedsAccessCheck()) {
5310    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5311    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5312                            cls,
5313                            cls->GetDexPc(),
5314                            nullptr);
5315    CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
5316    return;
5317  }
5318
5319  Location out_loc = locations->Out();
5320  Register out = out_loc.AsRegister<Register>();
5321
5322  bool generate_null_check = false;
5323  switch (cls->GetLoadKind()) {
5324    case HLoadClass::LoadKind::kReferrersClass: {
5325      DCHECK(!cls->CanCallRuntime());
5326      DCHECK(!cls->MustGenerateClinitCheck());
5327      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5328      Register current_method = locations->InAt(0).AsRegister<Register>();
5329      GenerateGcRootFieldLoad(
5330          cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5331      break;
5332    }
5333    case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
5334      DCHECK(!kEmitCompilerReadBarrier);
5335      __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5336                                                                    cls->GetTypeIndex()));
5337      break;
5338    }
5339    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5340      DCHECK(!kEmitCompilerReadBarrier);
5341      CodeGeneratorARM::PcRelativePatchInfo* labels =
5342          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5343      __ BindTrackedLabel(&labels->movw_label);
5344      __ movw(out, /* placeholder */ 0u);
5345      __ BindTrackedLabel(&labels->movt_label);
5346      __ movt(out, /* placeholder */ 0u);
5347      __ BindTrackedLabel(&labels->add_pc_label);
5348      __ add(out, out, ShifterOperand(PC));
5349      break;
5350    }
5351    case HLoadClass::LoadKind::kBootImageAddress: {
5352      DCHECK(!kEmitCompilerReadBarrier);
5353      DCHECK_NE(cls->GetAddress(), 0u);
5354      uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5355      __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5356      break;
5357    }
5358    case HLoadClass::LoadKind::kDexCacheAddress: {
5359      DCHECK_NE(cls->GetAddress(), 0u);
5360      uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5361      // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5362      // a 128B range. To try and reduce the number of literals if we load multiple types,
5363      // simply split the dex cache address to a 128B aligned base loaded from a literal
5364      // and the remaining offset embedded in the load.
5365      static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
5366      DCHECK_ALIGNED(cls->GetAddress(), 4u);
5367      constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5368      uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5369      uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5370      __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5371      // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
5372      GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5373      generate_null_check = !cls->IsInDexCache();
5374      break;
5375    }
5376    case HLoadClass::LoadKind::kDexCachePcRelative: {
5377      Register base_reg = locations->InAt(0).AsRegister<Register>();
5378      HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase();
5379      int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset();
5380      // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
5381      GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset);
5382      generate_null_check = !cls->IsInDexCache();
5383      break;
5384    }
5385    case HLoadClass::LoadKind::kDexCacheViaMethod: {
5386      // /* GcRoot<mirror::Class>[] */ out =
5387      //        current_method.ptr_sized_fields_->dex_cache_resolved_types_
5388      Register current_method = locations->InAt(0).AsRegister<Register>();
5389      __ LoadFromOffset(kLoadWord,
5390                        out,
5391                        current_method,
5392                        ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5393      // /* GcRoot<mirror::Class> */ out = out[type_index]
5394      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5395      GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5396      generate_null_check = !cls->IsInDexCache();
5397    }
5398  }
5399
5400  if (generate_null_check || cls->MustGenerateClinitCheck()) {
5401    DCHECK(cls->CanCallRuntime());
5402    SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5403        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5404    codegen_->AddSlowPath(slow_path);
5405    if (generate_null_check) {
5406      __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5407    }
5408    if (cls->MustGenerateClinitCheck()) {
5409      GenerateClassInitializationCheck(slow_path, out);
5410    } else {
5411      __ Bind(slow_path->GetExitLabel());
5412    }
5413  }
5414}
5415
5416void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5417  LocationSummary* locations =
5418      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5419  locations->SetInAt(0, Location::RequiresRegister());
5420  if (check->HasUses()) {
5421    locations->SetOut(Location::SameAsFirstInput());
5422  }
5423}
5424
5425void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
5426  // We assume the class is not null.
5427  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5428      check->GetLoadClass(), check, check->GetDexPc(), true);
5429  codegen_->AddSlowPath(slow_path);
5430  GenerateClassInitializationCheck(slow_path,
5431                                   check->GetLocations()->InAt(0).AsRegister<Register>());
5432}
5433
5434void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
5435    SlowPathCode* slow_path, Register class_reg) {
5436  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5437  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5438  __ b(slow_path->GetEntryLabel(), LT);
5439  // Even if the initialized flag is set, we may be in a situation where caches are not synced
5440  // properly. Therefore, we do a memory fence.
5441  __ dmb(ISH);
5442  __ Bind(slow_path->GetExitLabel());
5443}
5444
5445HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5446    HLoadString::LoadKind desired_string_load_kind) {
5447  if (kEmitCompilerReadBarrier) {
5448    switch (desired_string_load_kind) {
5449      case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5450      case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5451      case HLoadString::LoadKind::kBootImageAddress:
5452        // TODO: Implement for read barrier.
5453        return HLoadString::LoadKind::kDexCacheViaMethod;
5454      default:
5455        break;
5456    }
5457  }
5458  switch (desired_string_load_kind) {
5459    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5460      DCHECK(!GetCompilerOptions().GetCompilePic());
5461      break;
5462    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5463      DCHECK(GetCompilerOptions().GetCompilePic());
5464      break;
5465    case HLoadString::LoadKind::kBootImageAddress:
5466      break;
5467    case HLoadString::LoadKind::kDexCacheAddress:
5468      DCHECK(Runtime::Current()->UseJitCompilation());
5469      break;
5470    case HLoadString::LoadKind::kDexCachePcRelative:
5471      DCHECK(!Runtime::Current()->UseJitCompilation());
5472      // We disable pc-relative load when there is an irreducible loop, as the optimization
5473      // is incompatible with it.
5474      // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5475      // with irreducible loops.
5476      if (GetGraph()->HasIrreducibleLoops()) {
5477        return HLoadString::LoadKind::kDexCacheViaMethod;
5478      }
5479      break;
5480    case HLoadString::LoadKind::kDexCacheViaMethod:
5481      break;
5482  }
5483  return desired_string_load_kind;
5484}
5485
5486void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5487  LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
5488      ? LocationSummary::kCallOnSlowPath
5489      : LocationSummary::kNoCall;
5490  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5491  HLoadString::LoadKind load_kind = load->GetLoadKind();
5492  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5493      load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5494    locations->SetInAt(0, Location::RequiresRegister());
5495  }
5496  locations->SetOut(Location::RequiresRegister());
5497}
5498
5499void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
5500  LocationSummary* locations = load->GetLocations();
5501  Location out_loc = locations->Out();
5502  Register out = out_loc.AsRegister<Register>();
5503
5504  switch (load->GetLoadKind()) {
5505    case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5506      DCHECK(!kEmitCompilerReadBarrier);
5507      __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5508                                                                      load->GetStringIndex()));
5509      return;  // No dex cache slow path.
5510    }
5511    case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5512      DCHECK(!kEmitCompilerReadBarrier);
5513      CodeGeneratorARM::PcRelativePatchInfo* labels =
5514          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5515      __ BindTrackedLabel(&labels->movw_label);
5516      __ movw(out, /* placeholder */ 0u);
5517      __ BindTrackedLabel(&labels->movt_label);
5518      __ movt(out, /* placeholder */ 0u);
5519      __ BindTrackedLabel(&labels->add_pc_label);
5520      __ add(out, out, ShifterOperand(PC));
5521      return;  // No dex cache slow path.
5522    }
5523    case HLoadString::LoadKind::kBootImageAddress: {
5524      DCHECK(!kEmitCompilerReadBarrier);
5525      DCHECK_NE(load->GetAddress(), 0u);
5526      uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5527      __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5528      return;  // No dex cache slow path.
5529    }
5530    case HLoadString::LoadKind::kDexCacheAddress: {
5531      DCHECK_NE(load->GetAddress(), 0u);
5532      uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5533      // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5534      // a 128B range. To try and reduce the number of literals if we load multiple strings,
5535      // simply split the dex cache address to a 128B aligned base loaded from a literal
5536      // and the remaining offset embedded in the load.
5537      static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5538      DCHECK_ALIGNED(load->GetAddress(), 4u);
5539      constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5540      uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5541      uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5542      __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5543      // /* GcRoot<mirror::String> */ out = *(base_address + offset)
5544      GenerateGcRootFieldLoad(load, out_loc, out, offset);
5545      break;
5546    }
5547    case HLoadString::LoadKind::kDexCachePcRelative: {
5548      Register base_reg = locations->InAt(0).AsRegister<Register>();
5549      HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5550      int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
5551      // /* GcRoot<mirror::String> */ out = *(dex_cache_arrays_base + offset)
5552      GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5553      break;
5554    }
5555    case HLoadString::LoadKind::kDexCacheViaMethod: {
5556      Register current_method = locations->InAt(0).AsRegister<Register>();
5557
5558      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5559      GenerateGcRootFieldLoad(
5560          load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5561      // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5562      __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5563      // /* GcRoot<mirror::String> */ out = out[string_index]
5564      GenerateGcRootFieldLoad(
5565          load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5566      break;
5567    }
5568    default:
5569      LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5570      UNREACHABLE();
5571  }
5572
5573  if (!load->IsInDexCache()) {
5574    SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5575    codegen_->AddSlowPath(slow_path);
5576    __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5577    __ Bind(slow_path->GetExitLabel());
5578  }
5579}
5580
5581static int32_t GetExceptionTlsOffset() {
5582  return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5583}
5584
5585void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5586  LocationSummary* locations =
5587      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5588  locations->SetOut(Location::RequiresRegister());
5589}
5590
5591void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
5592  Register out = load->GetLocations()->Out().AsRegister<Register>();
5593  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5594}
5595
5596void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5597  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5598}
5599
5600void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5601  __ LoadImmediate(IP, 0);
5602  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
5603}
5604
5605void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5606  LocationSummary* locations =
5607      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
5608  InvokeRuntimeCallingConvention calling_convention;
5609  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5610}
5611
5612void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5613  codegen_->InvokeRuntime(
5614      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
5615  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5616}
5617
5618static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5619  return kEmitCompilerReadBarrier &&
5620      (kUseBakerReadBarrier ||
5621       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5622       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5623       type_check_kind == TypeCheckKind::kArrayObjectCheck);
5624}
5625
5626void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
5627  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5628  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5629  switch (type_check_kind) {
5630    case TypeCheckKind::kExactCheck:
5631    case TypeCheckKind::kAbstractClassCheck:
5632    case TypeCheckKind::kClassHierarchyCheck:
5633    case TypeCheckKind::kArrayObjectCheck:
5634      call_kind =
5635          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
5636      break;
5637    case TypeCheckKind::kArrayCheck:
5638    case TypeCheckKind::kUnresolvedCheck:
5639    case TypeCheckKind::kInterfaceCheck:
5640      call_kind = LocationSummary::kCallOnSlowPath;
5641      break;
5642  }
5643
5644  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5645  locations->SetInAt(0, Location::RequiresRegister());
5646  locations->SetInAt(1, Location::RequiresRegister());
5647  // The "out" register is used as a temporary, so it overlaps with the inputs.
5648  // Note that TypeCheckSlowPathARM uses this register too.
5649  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5650  // When read barriers are enabled, we need a temporary register for
5651  // some cases.
5652  if (TypeCheckNeedsATemporary(type_check_kind)) {
5653    locations->AddTemp(Location::RequiresRegister());
5654  }
5655}
5656
5657void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
5658  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5659  LocationSummary* locations = instruction->GetLocations();
5660  Location obj_loc = locations->InAt(0);
5661  Register obj = obj_loc.AsRegister<Register>();
5662  Register cls = locations->InAt(1).AsRegister<Register>();
5663  Location out_loc = locations->Out();
5664  Register out = out_loc.AsRegister<Register>();
5665  Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
5666      locations->GetTemp(0) :
5667      Location::NoLocation();
5668  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5669  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5670  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5671  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5672  Label done, zero;
5673  SlowPathCode* slow_path = nullptr;
5674
5675  // Return 0 if `obj` is null.
5676  // avoid null check if we know obj is not null.
5677  if (instruction->MustDoNullCheck()) {
5678    __ CompareAndBranchIfZero(obj, &zero);
5679  }
5680
5681  // /* HeapReference<Class> */ out = obj->klass_
5682  GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
5683
5684  switch (type_check_kind) {
5685    case TypeCheckKind::kExactCheck: {
5686      __ cmp(out, ShifterOperand(cls));
5687      // Classes must be equal for the instanceof to succeed.
5688      __ b(&zero, NE);
5689      __ LoadImmediate(out, 1);
5690      __ b(&done);
5691      break;
5692    }
5693
5694    case TypeCheckKind::kAbstractClassCheck: {
5695      // If the class is abstract, we eagerly fetch the super class of the
5696      // object to avoid doing a comparison we know will fail.
5697      Label loop;
5698      __ Bind(&loop);
5699      // /* HeapReference<Class> */ out = out->super_class_
5700      GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
5701      // If `out` is null, we use it for the result, and jump to `done`.
5702      __ CompareAndBranchIfZero(out, &done);
5703      __ cmp(out, ShifterOperand(cls));
5704      __ b(&loop, NE);
5705      __ LoadImmediate(out, 1);
5706      if (zero.IsLinked()) {
5707        __ b(&done);
5708      }
5709      break;
5710    }
5711
5712    case TypeCheckKind::kClassHierarchyCheck: {
5713      // Walk over the class hierarchy to find a match.
5714      Label loop, success;
5715      __ Bind(&loop);
5716      __ cmp(out, ShifterOperand(cls));
5717      __ b(&success, EQ);
5718      // /* HeapReference<Class> */ out = out->super_class_
5719      GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
5720      __ CompareAndBranchIfNonZero(out, &loop);
5721      // If `out` is null, we use it for the result, and jump to `done`.
5722      __ b(&done);
5723      __ Bind(&success);
5724      __ LoadImmediate(out, 1);
5725      if (zero.IsLinked()) {
5726        __ b(&done);
5727      }
5728      break;
5729    }
5730
5731    case TypeCheckKind::kArrayObjectCheck: {
5732      // Do an exact check.
5733      Label exact_check;
5734      __ cmp(out, ShifterOperand(cls));
5735      __ b(&exact_check, EQ);
5736      // Otherwise, we need to check that the object's class is a non-primitive array.
5737      // /* HeapReference<Class> */ out = out->component_type_
5738      GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
5739      // If `out` is null, we use it for the result, and jump to `done`.
5740      __ CompareAndBranchIfZero(out, &done);
5741      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5742      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5743      __ CompareAndBranchIfNonZero(out, &zero);
5744      __ Bind(&exact_check);
5745      __ LoadImmediate(out, 1);
5746      __ b(&done);
5747      break;
5748    }
5749
5750    case TypeCheckKind::kArrayCheck: {
5751      __ cmp(out, ShifterOperand(cls));
5752      DCHECK(locations->OnlyCallsOnSlowPath());
5753      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5754                                                                    /* is_fatal */ false);
5755      codegen_->AddSlowPath(slow_path);
5756      __ b(slow_path->GetEntryLabel(), NE);
5757      __ LoadImmediate(out, 1);
5758      if (zero.IsLinked()) {
5759        __ b(&done);
5760      }
5761      break;
5762    }
5763
5764    case TypeCheckKind::kUnresolvedCheck:
5765    case TypeCheckKind::kInterfaceCheck: {
5766      // Note that we indeed only call on slow path, but we always go
5767      // into the slow path for the unresolved and interface check
5768      // cases.
5769      //
5770      // We cannot directly call the InstanceofNonTrivial runtime
5771      // entry point without resorting to a type checking slow path
5772      // here (i.e. by calling InvokeRuntime directly), as it would
5773      // require to assign fixed registers for the inputs of this
5774      // HInstanceOf instruction (following the runtime calling
5775      // convention), which might be cluttered by the potential first
5776      // read barrier emission at the beginning of this method.
5777      //
5778      // TODO: Introduce a new runtime entry point taking the object
5779      // to test (instead of its class) as argument, and let it deal
5780      // with the read barrier issues. This will let us refactor this
5781      // case of the `switch` code as it was previously (with a direct
5782      // call to the runtime not using a type checking slow path).
5783      // This should also be beneficial for the other cases above.
5784      DCHECK(locations->OnlyCallsOnSlowPath());
5785      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5786                                                                    /* is_fatal */ false);
5787      codegen_->AddSlowPath(slow_path);
5788      __ b(slow_path->GetEntryLabel());
5789      if (zero.IsLinked()) {
5790        __ b(&done);
5791      }
5792      break;
5793    }
5794  }
5795
5796  if (zero.IsLinked()) {
5797    __ Bind(&zero);
5798    __ LoadImmediate(out, 0);
5799  }
5800
5801  if (done.IsLinked()) {
5802    __ Bind(&done);
5803  }
5804
5805  if (slow_path != nullptr) {
5806    __ Bind(slow_path->GetExitLabel());
5807  }
5808}
5809
5810void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
5811  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5812  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5813
5814  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5815  switch (type_check_kind) {
5816    case TypeCheckKind::kExactCheck:
5817    case TypeCheckKind::kAbstractClassCheck:
5818    case TypeCheckKind::kClassHierarchyCheck:
5819    case TypeCheckKind::kArrayObjectCheck:
5820      call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5821          LocationSummary::kCallOnSlowPath :
5822          LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
5823      break;
5824    case TypeCheckKind::kArrayCheck:
5825    case TypeCheckKind::kUnresolvedCheck:
5826    case TypeCheckKind::kInterfaceCheck:
5827      call_kind = LocationSummary::kCallOnSlowPath;
5828      break;
5829  }
5830
5831  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5832  locations->SetInAt(0, Location::RequiresRegister());
5833  locations->SetInAt(1, Location::RequiresRegister());
5834  // Note that TypeCheckSlowPathARM uses this "temp" register too.
5835  locations->AddTemp(Location::RequiresRegister());
5836  // When read barriers are enabled, we need an additional temporary
5837  // register for some cases.
5838  if (TypeCheckNeedsATemporary(type_check_kind)) {
5839    locations->AddTemp(Location::RequiresRegister());
5840  }
5841}
5842
5843void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5844  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5845  LocationSummary* locations = instruction->GetLocations();
5846  Location obj_loc = locations->InAt(0);
5847  Register obj = obj_loc.AsRegister<Register>();
5848  Register cls = locations->InAt(1).AsRegister<Register>();
5849  Location temp_loc = locations->GetTemp(0);
5850  Register temp = temp_loc.AsRegister<Register>();
5851  Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
5852      locations->GetTemp(1) :
5853      Location::NoLocation();
5854  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5855  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5856  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5857  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5858
5859  bool is_type_check_slow_path_fatal =
5860      (type_check_kind == TypeCheckKind::kExactCheck ||
5861       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5862       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5863       type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5864      !instruction->CanThrowIntoCatchBlock();
5865  SlowPathCode* type_check_slow_path =
5866      new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5867                                                        is_type_check_slow_path_fatal);
5868  codegen_->AddSlowPath(type_check_slow_path);
5869
5870  Label done;
5871  // Avoid null check if we know obj is not null.
5872  if (instruction->MustDoNullCheck()) {
5873    __ CompareAndBranchIfZero(obj, &done);
5874  }
5875
5876  // /* HeapReference<Class> */ temp = obj->klass_
5877  GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5878
5879  switch (type_check_kind) {
5880    case TypeCheckKind::kExactCheck:
5881    case TypeCheckKind::kArrayCheck: {
5882      __ cmp(temp, ShifterOperand(cls));
5883      // Jump to slow path for throwing the exception or doing a
5884      // more involved array check.
5885      __ b(type_check_slow_path->GetEntryLabel(), NE);
5886      break;
5887    }
5888
5889    case TypeCheckKind::kAbstractClassCheck: {
5890      // If the class is abstract, we eagerly fetch the super class of the
5891      // object to avoid doing a comparison we know will fail.
5892      Label loop, compare_classes;
5893      __ Bind(&loop);
5894      // /* HeapReference<Class> */ temp = temp->super_class_
5895      GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
5896
5897      // If the class reference currently in `temp` is not null, jump
5898      // to the `compare_classes` label to compare it with the checked
5899      // class.
5900      __ CompareAndBranchIfNonZero(temp, &compare_classes);
5901      // Otherwise, jump to the slow path to throw the exception.
5902      //
5903      // But before, move back the object's class into `temp` before
5904      // going into the slow path, as it has been overwritten in the
5905      // meantime.
5906      // /* HeapReference<Class> */ temp = obj->klass_
5907      GenerateReferenceLoadTwoRegisters(
5908          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5909      __ b(type_check_slow_path->GetEntryLabel());
5910
5911      __ Bind(&compare_classes);
5912      __ cmp(temp, ShifterOperand(cls));
5913      __ b(&loop, NE);
5914      break;
5915    }
5916
5917    case TypeCheckKind::kClassHierarchyCheck: {
5918      // Walk over the class hierarchy to find a match.
5919      Label loop;
5920      __ Bind(&loop);
5921      __ cmp(temp, ShifterOperand(cls));
5922      __ b(&done, EQ);
5923
5924      // /* HeapReference<Class> */ temp = temp->super_class_
5925      GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
5926
5927      // If the class reference currently in `temp` is not null, jump
5928      // back at the beginning of the loop.
5929      __ CompareAndBranchIfNonZero(temp, &loop);
5930      // Otherwise, jump to the slow path to throw the exception.
5931      //
5932      // But before, move back the object's class into `temp` before
5933      // going into the slow path, as it has been overwritten in the
5934      // meantime.
5935      // /* HeapReference<Class> */ temp = obj->klass_
5936      GenerateReferenceLoadTwoRegisters(
5937          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5938      __ b(type_check_slow_path->GetEntryLabel());
5939      break;
5940    }
5941
5942    case TypeCheckKind::kArrayObjectCheck: {
5943      // Do an exact check.
5944      Label check_non_primitive_component_type;
5945      __ cmp(temp, ShifterOperand(cls));
5946      __ b(&done, EQ);
5947
5948      // Otherwise, we need to check that the object's class is a non-primitive array.
5949      // /* HeapReference<Class> */ temp = temp->component_type_
5950      GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
5951
5952      // If the component type is not null (i.e. the object is indeed
5953      // an array), jump to label `check_non_primitive_component_type`
5954      // to further check that this component type is not a primitive
5955      // type.
5956      __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5957      // Otherwise, jump to the slow path to throw the exception.
5958      //
5959      // But before, move back the object's class into `temp` before
5960      // going into the slow path, as it has been overwritten in the
5961      // meantime.
5962      // /* HeapReference<Class> */ temp = obj->klass_
5963      GenerateReferenceLoadTwoRegisters(
5964          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5965      __ b(type_check_slow_path->GetEntryLabel());
5966
5967      __ Bind(&check_non_primitive_component_type);
5968      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5969      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5970      __ CompareAndBranchIfZero(temp, &done);
5971      // Same comment as above regarding `temp` and the slow path.
5972      // /* HeapReference<Class> */ temp = obj->klass_
5973      GenerateReferenceLoadTwoRegisters(
5974          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
5975      __ b(type_check_slow_path->GetEntryLabel());
5976      break;
5977    }
5978
5979    case TypeCheckKind::kUnresolvedCheck:
5980    case TypeCheckKind::kInterfaceCheck:
5981      // We always go into the type check slow path for the unresolved
5982      // and interface check cases.
5983      //
5984      // We cannot directly call the CheckCast runtime entry point
5985      // without resorting to a type checking slow path here (i.e. by
5986      // calling InvokeRuntime directly), as it would require to
5987      // assign fixed registers for the inputs of this HInstanceOf
5988      // instruction (following the runtime calling convention), which
5989      // might be cluttered by the potential first read barrier
5990      // emission at the beginning of this method.
5991      //
5992      // TODO: Introduce a new runtime entry point taking the object
5993      // to test (instead of its class) as argument, and let it deal
5994      // with the read barrier issues. This will let us refactor this
5995      // case of the `switch` code as it was previously (with a direct
5996      // call to the runtime not using a type checking slow path).
5997      // This should also be beneficial for the other cases above.
5998      __ b(type_check_slow_path->GetEntryLabel());
5999      break;
6000  }
6001  __ Bind(&done);
6002
6003  __ Bind(type_check_slow_path->GetExitLabel());
6004}
6005
6006void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6007  LocationSummary* locations =
6008      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
6009  InvokeRuntimeCallingConvention calling_convention;
6010  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6011}
6012
6013void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6014  codegen_->InvokeRuntime(instruction->IsEnter()
6015        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
6016      instruction,
6017      instruction->GetDexPc(),
6018      nullptr);
6019  if (instruction->IsEnter()) {
6020    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6021  } else {
6022    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6023  }
6024}
6025
6026void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
6027void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
6028void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
6029
6030void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
6031  LocationSummary* locations =
6032      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6033  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6034         || instruction->GetResultType() == Primitive::kPrimLong);
6035  // Note: GVN reorders commutative operations to have the constant on the right hand side.
6036  locations->SetInAt(0, Location::RequiresRegister());
6037  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
6038  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6039}
6040
6041void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
6042  HandleBitwiseOperation(instruction);
6043}
6044
6045void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
6046  HandleBitwiseOperation(instruction);
6047}
6048
6049void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
6050  HandleBitwiseOperation(instruction);
6051}
6052
6053
6054void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6055  LocationSummary* locations =
6056      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6057  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6058         || instruction->GetResultType() == Primitive::kPrimLong);
6059
6060  locations->SetInAt(0, Location::RequiresRegister());
6061  locations->SetInAt(1, Location::RequiresRegister());
6062  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6063}
6064
6065void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6066  LocationSummary* locations = instruction->GetLocations();
6067  Location first = locations->InAt(0);
6068  Location second = locations->InAt(1);
6069  Location out = locations->Out();
6070
6071  if (instruction->GetResultType() == Primitive::kPrimInt) {
6072    Register first_reg = first.AsRegister<Register>();
6073    ShifterOperand second_reg(second.AsRegister<Register>());
6074    Register out_reg = out.AsRegister<Register>();
6075
6076    switch (instruction->GetOpKind()) {
6077      case HInstruction::kAnd:
6078        __ bic(out_reg, first_reg, second_reg);
6079        break;
6080      case HInstruction::kOr:
6081        __ orn(out_reg, first_reg, second_reg);
6082        break;
6083      // There is no EON on arm.
6084      case HInstruction::kXor:
6085      default:
6086        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6087        UNREACHABLE();
6088    }
6089    return;
6090
6091  } else {
6092    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6093    Register first_low = first.AsRegisterPairLow<Register>();
6094    Register first_high = first.AsRegisterPairHigh<Register>();
6095    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6096    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6097    Register out_low = out.AsRegisterPairLow<Register>();
6098    Register out_high = out.AsRegisterPairHigh<Register>();
6099
6100    switch (instruction->GetOpKind()) {
6101      case HInstruction::kAnd:
6102        __ bic(out_low, first_low, second_low);
6103        __ bic(out_high, first_high, second_high);
6104        break;
6105      case HInstruction::kOr:
6106        __ orn(out_low, first_low, second_low);
6107        __ orn(out_high, first_high, second_high);
6108        break;
6109      // There is no EON on arm.
6110      case HInstruction::kXor:
6111      default:
6112        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6113        UNREACHABLE();
6114    }
6115  }
6116}
6117
6118void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
6119  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
6120  if (value == 0xffffffffu) {
6121    if (out != first) {
6122      __ mov(out, ShifterOperand(first));
6123    }
6124    return;
6125  }
6126  if (value == 0u) {
6127    __ mov(out, ShifterOperand(0));
6128    return;
6129  }
6130  ShifterOperand so;
6131  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
6132    __ and_(out, first, so);
6133  } else {
6134    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
6135    __ bic(out, first, ShifterOperand(~value));
6136  }
6137}
6138
6139void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
6140  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
6141  if (value == 0u) {
6142    if (out != first) {
6143      __ mov(out, ShifterOperand(first));
6144    }
6145    return;
6146  }
6147  if (value == 0xffffffffu) {
6148    __ mvn(out, ShifterOperand(0));
6149    return;
6150  }
6151  ShifterOperand so;
6152  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
6153    __ orr(out, first, so);
6154  } else {
6155    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
6156    __ orn(out, first, ShifterOperand(~value));
6157  }
6158}
6159
6160void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6161  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6162  if (value == 0u) {
6163    if (out != first) {
6164      __ mov(out, ShifterOperand(first));
6165    }
6166    return;
6167  }
6168  __ eor(out, first, ShifterOperand(value));
6169}
6170
6171void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6172  LocationSummary* locations = instruction->GetLocations();
6173  Location first = locations->InAt(0);
6174  Location second = locations->InAt(1);
6175  Location out = locations->Out();
6176
6177  if (second.IsConstant()) {
6178    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6179    uint32_t value_low = Low32Bits(value);
6180    if (instruction->GetResultType() == Primitive::kPrimInt) {
6181      Register first_reg = first.AsRegister<Register>();
6182      Register out_reg = out.AsRegister<Register>();
6183      if (instruction->IsAnd()) {
6184        GenerateAndConst(out_reg, first_reg, value_low);
6185      } else if (instruction->IsOr()) {
6186        GenerateOrrConst(out_reg, first_reg, value_low);
6187      } else {
6188        DCHECK(instruction->IsXor());
6189        GenerateEorConst(out_reg, first_reg, value_low);
6190      }
6191    } else {
6192      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6193      uint32_t value_high = High32Bits(value);
6194      Register first_low = first.AsRegisterPairLow<Register>();
6195      Register first_high = first.AsRegisterPairHigh<Register>();
6196      Register out_low = out.AsRegisterPairLow<Register>();
6197      Register out_high = out.AsRegisterPairHigh<Register>();
6198      if (instruction->IsAnd()) {
6199        GenerateAndConst(out_low, first_low, value_low);
6200        GenerateAndConst(out_high, first_high, value_high);
6201      } else if (instruction->IsOr()) {
6202        GenerateOrrConst(out_low, first_low, value_low);
6203        GenerateOrrConst(out_high, first_high, value_high);
6204      } else {
6205        DCHECK(instruction->IsXor());
6206        GenerateEorConst(out_low, first_low, value_low);
6207        GenerateEorConst(out_high, first_high, value_high);
6208      }
6209    }
6210    return;
6211  }
6212
6213  if (instruction->GetResultType() == Primitive::kPrimInt) {
6214    Register first_reg = first.AsRegister<Register>();
6215    ShifterOperand second_reg(second.AsRegister<Register>());
6216    Register out_reg = out.AsRegister<Register>();
6217    if (instruction->IsAnd()) {
6218      __ and_(out_reg, first_reg, second_reg);
6219    } else if (instruction->IsOr()) {
6220      __ orr(out_reg, first_reg, second_reg);
6221    } else {
6222      DCHECK(instruction->IsXor());
6223      __ eor(out_reg, first_reg, second_reg);
6224    }
6225  } else {
6226    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6227    Register first_low = first.AsRegisterPairLow<Register>();
6228    Register first_high = first.AsRegisterPairHigh<Register>();
6229    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6230    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6231    Register out_low = out.AsRegisterPairLow<Register>();
6232    Register out_high = out.AsRegisterPairHigh<Register>();
6233    if (instruction->IsAnd()) {
6234      __ and_(out_low, first_low, second_low);
6235      __ and_(out_high, first_high, second_high);
6236    } else if (instruction->IsOr()) {
6237      __ orr(out_low, first_low, second_low);
6238      __ orr(out_high, first_high, second_high);
6239    } else {
6240      DCHECK(instruction->IsXor());
6241      __ eor(out_low, first_low, second_low);
6242      __ eor(out_high, first_high, second_high);
6243    }
6244  }
6245}
6246
6247void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
6248                                                                   Location out,
6249                                                                   uint32_t offset,
6250                                                                   Location maybe_temp) {
6251  Register out_reg = out.AsRegister<Register>();
6252  if (kEmitCompilerReadBarrier) {
6253    DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6254    if (kUseBakerReadBarrier) {
6255      // Load with fast path based Baker's read barrier.
6256      // /* HeapReference<Object> */ out = *(out + offset)
6257      codegen_->GenerateFieldLoadWithBakerReadBarrier(
6258          instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
6259    } else {
6260      // Load with slow path based read barrier.
6261      // Save the value of `out` into `maybe_temp` before overwriting it
6262      // in the following move operation, as we will need it for the
6263      // read barrier below.
6264      __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
6265      // /* HeapReference<Object> */ out = *(out + offset)
6266      __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6267      codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6268    }
6269  } else {
6270    // Plain load with no read barrier.
6271    // /* HeapReference<Object> */ out = *(out + offset)
6272    __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6273    __ MaybeUnpoisonHeapReference(out_reg);
6274  }
6275}
6276
6277void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6278                                                                    Location out,
6279                                                                    Location obj,
6280                                                                    uint32_t offset,
6281                                                                    Location maybe_temp) {
6282  Register out_reg = out.AsRegister<Register>();
6283  Register obj_reg = obj.AsRegister<Register>();
6284  if (kEmitCompilerReadBarrier) {
6285    if (kUseBakerReadBarrier) {
6286      DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6287      // Load with fast path based Baker's read barrier.
6288      // /* HeapReference<Object> */ out = *(obj + offset)
6289      codegen_->GenerateFieldLoadWithBakerReadBarrier(
6290          instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
6291    } else {
6292      // Load with slow path based read barrier.
6293      // /* HeapReference<Object> */ out = *(obj + offset)
6294      __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6295      codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6296    }
6297  } else {
6298    // Plain load with no read barrier.
6299    // /* HeapReference<Object> */ out = *(obj + offset)
6300    __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6301    __ MaybeUnpoisonHeapReference(out_reg);
6302  }
6303}
6304
6305void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6306                                                          Location root,
6307                                                          Register obj,
6308                                                          uint32_t offset) {
6309  Register root_reg = root.AsRegister<Register>();
6310  if (kEmitCompilerReadBarrier) {
6311    if (kUseBakerReadBarrier) {
6312      // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6313      // Baker's read barrier are used:
6314      //
6315      //   root = obj.field;
6316      //   if (Thread::Current()->GetIsGcMarking()) {
6317      //     root = ReadBarrier::Mark(root)
6318      //   }
6319
6320      // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6321      __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6322      static_assert(
6323          sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6324          "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6325          "have different sizes.");
6326      static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6327                    "art::mirror::CompressedReference<mirror::Object> and int32_t "
6328                    "have different sizes.");
6329
6330      // Slow path used to mark the GC root `root`.
6331      SlowPathCode* slow_path =
6332          new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root);
6333      codegen_->AddSlowPath(slow_path);
6334
6335      // IP = Thread::Current()->GetIsGcMarking()
6336      __ LoadFromOffset(
6337          kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6338      __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6339      __ Bind(slow_path->GetExitLabel());
6340    } else {
6341      // GC root loaded through a slow path for read barriers other
6342      // than Baker's.
6343      // /* GcRoot<mirror::Object>* */ root = obj + offset
6344      __ AddConstant(root_reg, obj, offset);
6345      // /* mirror::Object* */ root = root->Read()
6346      codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6347    }
6348  } else {
6349    // Plain GC root load with no read barrier.
6350    // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6351    __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6352    // Note that GC roots are not affected by heap poisoning, thus we
6353    // do not have to unpoison `root_reg` here.
6354  }
6355}
6356
6357void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6358                                                             Location ref,
6359                                                             Register obj,
6360                                                             uint32_t offset,
6361                                                             Location temp,
6362                                                             bool needs_null_check) {
6363  DCHECK(kEmitCompilerReadBarrier);
6364  DCHECK(kUseBakerReadBarrier);
6365
6366  // /* HeapReference<Object> */ ref = *(obj + offset)
6367  Location no_index = Location::NoLocation();
6368  ScaleFactor no_scale_factor = TIMES_1;
6369  GenerateReferenceLoadWithBakerReadBarrier(
6370      instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
6371}
6372
6373void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6374                                                             Location ref,
6375                                                             Register obj,
6376                                                             uint32_t data_offset,
6377                                                             Location index,
6378                                                             Location temp,
6379                                                             bool needs_null_check) {
6380  DCHECK(kEmitCompilerReadBarrier);
6381  DCHECK(kUseBakerReadBarrier);
6382
6383  static_assert(
6384      sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6385      "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6386  // /* HeapReference<Object> */ ref =
6387  //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
6388  ScaleFactor scale_factor = TIMES_4;
6389  GenerateReferenceLoadWithBakerReadBarrier(
6390      instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
6391}
6392
6393void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6394                                                                 Location ref,
6395                                                                 Register obj,
6396                                                                 uint32_t offset,
6397                                                                 Location index,
6398                                                                 ScaleFactor scale_factor,
6399                                                                 Location temp,
6400                                                                 bool needs_null_check) {
6401  DCHECK(kEmitCompilerReadBarrier);
6402  DCHECK(kUseBakerReadBarrier);
6403
6404  // In slow path based read barriers, the read barrier call is
6405  // inserted after the original load. However, in fast path based
6406  // Baker's read barriers, we need to perform the load of
6407  // mirror::Object::monitor_ *before* the original reference load.
6408  // This load-load ordering is required by the read barrier.
6409  // The fast path/slow path (for Baker's algorithm) should look like:
6410  //
6411  //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6412  //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
6413  //   HeapReference<Object> ref = *src;  // Original reference load.
6414  //   bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6415  //   if (is_gray) {
6416  //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
6417  //   }
6418  //
6419  // Note: the original implementation in ReadBarrier::Barrier is
6420  // slightly more complex as it performs additional checks that we do
6421  // not do here for performance reasons.
6422
6423  Register ref_reg = ref.AsRegister<Register>();
6424  Register temp_reg = temp.AsRegister<Register>();
6425  uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6426
6427  // /* int32_t */ monitor = obj->monitor_
6428  __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6429  if (needs_null_check) {
6430    MaybeRecordImplicitNullCheck(instruction);
6431  }
6432  // /* LockWord */ lock_word = LockWord(monitor)
6433  static_assert(sizeof(LockWord) == sizeof(int32_t),
6434                "art::LockWord and int32_t have different sizes.");
6435
6436  // Introduce a dependency on the lock_word including the rb_state,
6437  // which shall prevent load-load reordering without using
6438  // a memory barrier (which would be more expensive).
6439  // obj is unchanged by this operation, but its value now depends on temp_reg.
6440  __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
6441
6442  // The actual reference load.
6443  if (index.IsValid()) {
6444    // Load types involving an "index": ArrayGet and
6445    // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
6446    // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
6447    if (index.IsConstant()) {
6448      size_t computed_offset =
6449          (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
6450      __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6451    } else {
6452      // Handle the special case of the
6453      // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use
6454      // a register pair as index ("long offset"), of which only the low
6455      // part contains data.
6456      Register index_reg = index.IsRegisterPair()
6457          ? index.AsRegisterPairLow<Register>()
6458          : index.AsRegister<Register>();
6459      __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
6460      __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6461    }
6462  } else {
6463    // /* HeapReference<Object> */ ref = *(obj + offset)
6464    __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6465  }
6466
6467  // Object* ref = ref_addr->AsMirrorPtr()
6468  __ MaybeUnpoisonHeapReference(ref_reg);
6469
6470  // Slow path used to mark the object `ref` when it is gray.
6471  SlowPathCode* slow_path =
6472      new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
6473  AddSlowPath(slow_path);
6474
6475  // if (rb_state == ReadBarrier::gray_ptr_)
6476  //   ref = ReadBarrier::Mark(ref);
6477  // Given the numeric representation, it's enough to check the low bit of the
6478  // rb_state. We do that by shifting the bit out of the lock word with LSRS
6479  // which can be a 16-bit instruction unlike the TST immediate.
6480  static_assert(ReadBarrier::white_ptr_ == 0, "Expecting white to have value 0");
6481  static_assert(ReadBarrier::gray_ptr_ == 1, "Expecting gray to have value 1");
6482  static_assert(ReadBarrier::black_ptr_ == 2, "Expecting black to have value 2");
6483  __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
6484  __ b(slow_path->GetEntryLabel(), CS);  // Carry flag is the last bit shifted out by LSRS.
6485  __ Bind(slow_path->GetExitLabel());
6486}
6487
6488void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6489                                               Location out,
6490                                               Location ref,
6491                                               Location obj,
6492                                               uint32_t offset,
6493                                               Location index) {
6494  DCHECK(kEmitCompilerReadBarrier);
6495
6496  // Insert a slow path based read barrier *after* the reference load.
6497  //
6498  // If heap poisoning is enabled, the unpoisoning of the loaded
6499  // reference will be carried out by the runtime within the slow
6500  // path.
6501  //
6502  // Note that `ref` currently does not get unpoisoned (when heap
6503  // poisoning is enabled), which is alright as the `ref` argument is
6504  // not used by the artReadBarrierSlow entry point.
6505  //
6506  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6507  SlowPathCode* slow_path = new (GetGraph()->GetArena())
6508      ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6509  AddSlowPath(slow_path);
6510
6511  __ b(slow_path->GetEntryLabel());
6512  __ Bind(slow_path->GetExitLabel());
6513}
6514
6515void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6516                                                    Location out,
6517                                                    Location ref,
6518                                                    Location obj,
6519                                                    uint32_t offset,
6520                                                    Location index) {
6521  if (kEmitCompilerReadBarrier) {
6522    // Baker's read barriers shall be handled by the fast path
6523    // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6524    DCHECK(!kUseBakerReadBarrier);
6525    // If heap poisoning is enabled, unpoisoning will be taken care of
6526    // by the runtime within the slow path.
6527    GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
6528  } else if (kPoisonHeapReferences) {
6529    __ UnpoisonHeapReference(out.AsRegister<Register>());
6530  }
6531}
6532
6533void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6534                                                      Location out,
6535                                                      Location root) {
6536  DCHECK(kEmitCompilerReadBarrier);
6537
6538  // Insert a slow path based read barrier *after* the GC root load.
6539  //
6540  // Note that GC roots are not affected by heap poisoning, so we do
6541  // not need to do anything special for this here.
6542  SlowPathCode* slow_path =
6543      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6544  AddSlowPath(slow_path);
6545
6546  __ b(slow_path->GetEntryLabel());
6547  __ Bind(slow_path->GetExitLabel());
6548}
6549
6550HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6551      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6552      MethodReference target_method) {
6553  HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6554  // We disable pc-relative load when there is an irreducible loop, as the optimization
6555  // is incompatible with it.
6556  // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6557  // with irreducible loops.
6558  if (GetGraph()->HasIrreducibleLoops() &&
6559      (dispatch_info.method_load_kind ==
6560          HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6561    dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6562  }
6563
6564  if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
6565    const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6566    if (&outer_dex_file != target_method.dex_file) {
6567      // Calls across dex files are more likely to exceed the available BL range,
6568      // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6569      HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6570          (desired_dispatch_info.method_load_kind ==
6571           HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6572          ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6573          : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6574      return HInvokeStaticOrDirect::DispatchInfo {
6575        dispatch_info.method_load_kind,
6576        code_ptr_location,
6577        dispatch_info.method_load_data,
6578        0u
6579      };
6580    }
6581  }
6582  return dispatch_info;
6583}
6584
6585Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6586                                                                 Register temp) {
6587  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6588  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6589  if (!invoke->GetLocations()->Intrinsified()) {
6590    return location.AsRegister<Register>();
6591  }
6592  // For intrinsics we allow any location, so it may be on the stack.
6593  if (!location.IsRegister()) {
6594    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6595    return temp;
6596  }
6597  // For register locations, check if the register was saved. If so, get it from the stack.
6598  // Note: There is a chance that the register was saved but not overwritten, so we could
6599  // save one load. However, since this is just an intrinsic slow path we prefer this
6600  // simple and more robust approach rather that trying to determine if that's the case.
6601  SlowPathCode* slow_path = GetCurrentSlowPath();
6602  DCHECK(slow_path != nullptr);  // For intrinsified invokes the call is emitted on the slow path.
6603  if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6604    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6605    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6606    return temp;
6607  }
6608  return location.AsRegister<Register>();
6609}
6610
6611void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
6612  // For better instruction scheduling we load the direct code pointer before the method pointer.
6613  switch (invoke->GetCodePtrLocation()) {
6614    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6615      // LR = code address from literal pool with link-time patch.
6616      __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
6617      break;
6618    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6619      // LR = invoke->GetDirectCodePtr();
6620      __ LoadImmediate(LR, invoke->GetDirectCodePtr());
6621      break;
6622    default:
6623      break;
6624  }
6625
6626  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
6627  switch (invoke->GetMethodLoadKind()) {
6628    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6629      // temp = thread->string_init_entrypoint
6630      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6631      break;
6632    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
6633      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6634      break;
6635    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6636      __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6637      break;
6638    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6639      __ LoadLiteral(temp.AsRegister<Register>(),
6640                     DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6641      break;
6642    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6643      HArmDexCacheArraysBase* base =
6644          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6645      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6646                                                                temp.AsRegister<Register>());
6647      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6648      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6649      break;
6650    }
6651    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
6652      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6653      Register method_reg;
6654      Register reg = temp.AsRegister<Register>();
6655      if (current_method.IsRegister()) {
6656        method_reg = current_method.AsRegister<Register>();
6657      } else {
6658        DCHECK(invoke->GetLocations()->Intrinsified());
6659        DCHECK(!current_method.IsValid());
6660        method_reg = reg;
6661        __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6662      }
6663      // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6664      __ LoadFromOffset(kLoadWord,
6665                        reg,
6666                        method_reg,
6667                        ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
6668      // temp = temp[index_in_cache];
6669      // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6670      uint32_t index_in_cache = invoke->GetDexMethodIndex();
6671      __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6672      break;
6673    }
6674  }
6675
6676  switch (invoke->GetCodePtrLocation()) {
6677    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6678      __ bl(GetFrameEntryLabel());
6679      break;
6680    case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
6681      relative_call_patches_.emplace_back(invoke->GetTargetMethod());
6682      __ BindTrackedLabel(&relative_call_patches_.back().label);
6683      // Arbitrarily branch to the BL itself, override at link time.
6684      __ bl(&relative_call_patches_.back().label);
6685      break;
6686    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6687    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6688      // LR prepared above for better instruction scheduling.
6689      // LR()
6690      __ blx(LR);
6691      break;
6692    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6693      // LR = callee_method->entry_point_from_quick_compiled_code_
6694      __ LoadFromOffset(
6695          kLoadWord, LR, callee_method.AsRegister<Register>(),
6696          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6697      // LR()
6698      __ blx(LR);
6699      break;
6700  }
6701
6702  DCHECK(!IsLeafMethod());
6703}
6704
6705void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6706  Register temp = temp_location.AsRegister<Register>();
6707  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6708      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
6709
6710  // Use the calling convention instead of the location of the receiver, as
6711  // intrinsics may have put the receiver in a different register. In the intrinsics
6712  // slow path, the arguments have been moved to the right place, so here we are
6713  // guaranteed that the receiver is the first register of the calling convention.
6714  InvokeDexCallingConvention calling_convention;
6715  Register receiver = calling_convention.GetRegisterAt(0);
6716  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6717  // /* HeapReference<Class> */ temp = receiver->klass_
6718  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
6719  MaybeRecordImplicitNullCheck(invoke);
6720  // Instead of simply (possibly) unpoisoning `temp` here, we should
6721  // emit a read barrier for the previous class reference load.
6722  // However this is not required in practice, as this is an
6723  // intermediate/temporary reference and because the current
6724  // concurrent copying collector keeps the from-space memory
6725  // intact/accessible until the end of the marking phase (the
6726  // concurrent copying collector may not in the future).
6727  __ MaybeUnpoisonHeapReference(temp);
6728  // temp = temp->GetMethodAt(method_offset);
6729  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6730      kArmWordSize).Int32Value();
6731  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6732  // LR = temp->GetEntryPoint();
6733  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6734  // LR();
6735  __ blx(LR);
6736}
6737
6738CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6739    const DexFile& dex_file, uint32_t string_index) {
6740  return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6741}
6742
6743CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
6744    const DexFile& dex_file, uint32_t type_index) {
6745  return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
6746}
6747
6748CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6749    const DexFile& dex_file, uint32_t element_offset) {
6750  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6751}
6752
6753CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6754    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6755  patches->emplace_back(dex_file, offset_or_index);
6756  return &patches->back();
6757}
6758
6759Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6760                                                             uint32_t string_index) {
6761  return boot_image_string_patches_.GetOrCreate(
6762      StringReference(&dex_file, string_index),
6763      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6764}
6765
6766Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
6767                                                           uint32_t type_index) {
6768  return boot_image_type_patches_.GetOrCreate(
6769      TypeReference(&dex_file, type_index),
6770      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6771}
6772
6773Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6774  bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6775  Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6776  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6777}
6778
6779Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6780  return DeduplicateUint32Literal(address, &uint32_literals_);
6781}
6782
6783void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6784  DCHECK(linker_patches->empty());
6785  size_t size =
6786      method_patches_.size() +
6787      call_patches_.size() +
6788      relative_call_patches_.size() +
6789      /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6790      boot_image_string_patches_.size() +
6791      /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
6792      boot_image_type_patches_.size() +
6793      /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() +
6794      boot_image_address_patches_.size();
6795  linker_patches->reserve(size);
6796  for (const auto& entry : method_patches_) {
6797    const MethodReference& target_method = entry.first;
6798    Literal* literal = entry.second;
6799    DCHECK(literal->GetLabel()->IsBound());
6800    uint32_t literal_offset = literal->GetLabel()->Position();
6801    linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6802                                                       target_method.dex_file,
6803                                                       target_method.dex_method_index));
6804  }
6805  for (const auto& entry : call_patches_) {
6806    const MethodReference& target_method = entry.first;
6807    Literal* literal = entry.second;
6808    DCHECK(literal->GetLabel()->IsBound());
6809    uint32_t literal_offset = literal->GetLabel()->Position();
6810    linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6811                                                     target_method.dex_file,
6812                                                     target_method.dex_method_index));
6813  }
6814  for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6815    uint32_t literal_offset = info.label.Position();
6816    linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6817                                                             info.target_method.dex_file,
6818                                                             info.target_method.dex_method_index));
6819  }
6820  for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6821    const DexFile& dex_file = info.target_dex_file;
6822    size_t base_element_offset = info.offset_or_index;
6823    DCHECK(info.add_pc_label.IsBound());
6824    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6825    // Add MOVW patch.
6826    DCHECK(info.movw_label.IsBound());
6827    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6828    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6829                                                              &dex_file,
6830                                                              add_pc_offset,
6831                                                              base_element_offset));
6832    // Add MOVT patch.
6833    DCHECK(info.movt_label.IsBound());
6834    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6835    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6836                                                              &dex_file,
6837                                                              add_pc_offset,
6838                                                              base_element_offset));
6839  }
6840  for (const auto& entry : boot_image_string_patches_) {
6841    const StringReference& target_string = entry.first;
6842    Literal* literal = entry.second;
6843    DCHECK(literal->GetLabel()->IsBound());
6844    uint32_t literal_offset = literal->GetLabel()->Position();
6845    linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6846                                                       target_string.dex_file,
6847                                                       target_string.string_index));
6848  }
6849  for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6850    const DexFile& dex_file = info.target_dex_file;
6851    uint32_t string_index = info.offset_or_index;
6852    DCHECK(info.add_pc_label.IsBound());
6853    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6854    // Add MOVW patch.
6855    DCHECK(info.movw_label.IsBound());
6856    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6857    linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6858                                                               &dex_file,
6859                                                               add_pc_offset,
6860                                                               string_index));
6861    // Add MOVT patch.
6862    DCHECK(info.movt_label.IsBound());
6863    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6864    linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6865                                                               &dex_file,
6866                                                               add_pc_offset,
6867                                                               string_index));
6868  }
6869  for (const auto& entry : boot_image_type_patches_) {
6870    const TypeReference& target_type = entry.first;
6871    Literal* literal = entry.second;
6872    DCHECK(literal->GetLabel()->IsBound());
6873    uint32_t literal_offset = literal->GetLabel()->Position();
6874    linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
6875                                                     target_type.dex_file,
6876                                                     target_type.type_index));
6877  }
6878  for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
6879    const DexFile& dex_file = info.target_dex_file;
6880    uint32_t type_index = info.offset_or_index;
6881    DCHECK(info.add_pc_label.IsBound());
6882    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6883    // Add MOVW patch.
6884    DCHECK(info.movw_label.IsBound());
6885    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6886    linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset,
6887                                                             &dex_file,
6888                                                             add_pc_offset,
6889                                                             type_index));
6890    // Add MOVT patch.
6891    DCHECK(info.movt_label.IsBound());
6892    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6893    linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset,
6894                                                             &dex_file,
6895                                                             add_pc_offset,
6896                                                             type_index));
6897  }
6898  for (const auto& entry : boot_image_address_patches_) {
6899    DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6900    Literal* literal = entry.second;
6901    DCHECK(literal->GetLabel()->IsBound());
6902    uint32_t literal_offset = literal->GetLabel()->Position();
6903    linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6904  }
6905}
6906
6907Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6908  return map->GetOrCreate(
6909      value,
6910      [this, value]() { return __ NewLiteral<uint32_t>(value); });
6911}
6912
6913Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6914                                                    MethodToLiteralMap* map) {
6915  return map->GetOrCreate(
6916      target_method,
6917      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6918}
6919
6920Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6921  return DeduplicateMethodLiteral(target_method, &method_patches_);
6922}
6923
6924Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6925  return DeduplicateMethodLiteral(target_method, &call_patches_);
6926}
6927
6928void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6929  LocationSummary* locations =
6930      new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6931  locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6932                     Location::RequiresRegister());
6933  locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6934  locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6935  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6936}
6937
6938void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6939  LocationSummary* locations = instr->GetLocations();
6940  Register res = locations->Out().AsRegister<Register>();
6941  Register accumulator =
6942      locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6943  Register mul_left =
6944      locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6945  Register mul_right =
6946      locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6947
6948  if (instr->GetOpKind() == HInstruction::kAdd) {
6949    __ mla(res, mul_left, mul_right, accumulator);
6950  } else {
6951    __ mls(res, mul_left, mul_right, accumulator);
6952  }
6953}
6954
6955void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6956  // Nothing to do, this should be removed during prepare for register allocator.
6957  LOG(FATAL) << "Unreachable";
6958}
6959
6960void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6961  // Nothing to do, this should be removed during prepare for register allocator.
6962  LOG(FATAL) << "Unreachable";
6963}
6964
6965// Simple implementation of packed switch - generate cascaded compare/jumps.
6966void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6967  LocationSummary* locations =
6968      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6969  locations->SetInAt(0, Location::RequiresRegister());
6970  if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
6971      codegen_->GetAssembler()->IsThumb()) {
6972    locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
6973    if (switch_instr->GetStartValue() != 0) {
6974      locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
6975    }
6976  }
6977}
6978
6979void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6980  int32_t lower_bound = switch_instr->GetStartValue();
6981  uint32_t num_entries = switch_instr->GetNumEntries();
6982  LocationSummary* locations = switch_instr->GetLocations();
6983  Register value_reg = locations->InAt(0).AsRegister<Register>();
6984  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6985
6986  if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
6987    // Create a series of compare/jumps.
6988    Register temp_reg = IP;
6989    // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6990    // the immediate, because IP is used as the destination register. For the other
6991    // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6992    // and they can be encoded in the instruction without making use of IP register.
6993    __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6994
6995    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6996    // Jump to successors[0] if value == lower_bound.
6997    __ b(codegen_->GetLabelOf(successors[0]), EQ);
6998    int32_t last_index = 0;
6999    for (; num_entries - last_index > 2; last_index += 2) {
7000      __ AddConstantSetFlags(temp_reg, temp_reg, -2);
7001      // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
7002      __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
7003      // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
7004      __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
7005    }
7006    if (num_entries - last_index == 2) {
7007      // The last missing case_value.
7008      __ CmpConstant(temp_reg, 1);
7009      __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
7010    }
7011
7012    // And the default for any other value.
7013    if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7014      __ b(codegen_->GetLabelOf(default_block));
7015    }
7016  } else {
7017    // Create a table lookup.
7018    Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
7019
7020    // Materialize a pointer to the switch table
7021    std::vector<Label*> labels(num_entries);
7022    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7023    for (uint32_t i = 0; i < num_entries; i++) {
7024      labels[i] = codegen_->GetLabelOf(successors[i]);
7025    }
7026    JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
7027
7028    // Remove the bias.
7029    Register key_reg;
7030    if (lower_bound != 0) {
7031      key_reg = locations->GetTemp(1).AsRegister<Register>();
7032      __ AddConstant(key_reg, value_reg, -lower_bound);
7033    } else {
7034      key_reg = value_reg;
7035    }
7036
7037    // Check whether the value is in the table, jump to default block if not.
7038    __ CmpConstant(key_reg, num_entries - 1);
7039    __ b(codegen_->GetLabelOf(default_block), Condition::HI);
7040
7041    // Load the displacement from the table.
7042    __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
7043
7044    // Dispatch is a direct add to the PC (for Thumb2).
7045    __ EmitJumpTableDispatch(table, temp_reg);
7046  }
7047}
7048
7049void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7050  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7051  locations->SetOut(Location::RequiresRegister());
7052}
7053
7054void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7055  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
7056  CodeGeneratorARM::PcRelativePatchInfo* labels =
7057      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
7058  __ BindTrackedLabel(&labels->movw_label);
7059  __ movw(base_reg, /* placeholder */ 0u);
7060  __ BindTrackedLabel(&labels->movt_label);
7061  __ movt(base_reg, /* placeholder */ 0u);
7062  __ BindTrackedLabel(&labels->add_pc_label);
7063  __ add(base_reg, base_reg, ShifterOperand(PC));
7064}
7065
7066void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7067  if (!trg.IsValid()) {
7068    DCHECK_EQ(type, Primitive::kPrimVoid);
7069    return;
7070  }
7071
7072  DCHECK_NE(type, Primitive::kPrimVoid);
7073
7074  Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
7075  if (return_loc.Equals(trg)) {
7076    return;
7077  }
7078
7079  // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
7080  //       with the last branch.
7081  if (type == Primitive::kPrimLong) {
7082    HParallelMove parallel_move(GetGraph()->GetArena());
7083    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
7084    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
7085    GetMoveResolver()->EmitNativeCode(&parallel_move);
7086  } else if (type == Primitive::kPrimDouble) {
7087    HParallelMove parallel_move(GetGraph()->GetArena());
7088    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
7089    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
7090    GetMoveResolver()->EmitNativeCode(&parallel_move);
7091  } else {
7092    // Let the parallel move resolver take care of all of this.
7093    HParallelMove parallel_move(GetGraph()->GetArena());
7094    parallel_move.AddMove(return_loc, trg, type, nullptr);
7095    GetMoveResolver()->EmitNativeCode(&parallel_move);
7096  }
7097}
7098
7099void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
7100  LocationSummary* locations =
7101      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7102  locations->SetInAt(0, Location::RequiresRegister());
7103  locations->SetOut(Location::RequiresRegister());
7104}
7105
7106void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
7107  LocationSummary* locations = instruction->GetLocations();
7108  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
7109    uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7110        instruction->GetIndex(), kArmPointerSize).SizeValue();
7111    __ LoadFromOffset(kLoadWord,
7112                      locations->Out().AsRegister<Register>(),
7113                      locations->InAt(0).AsRegister<Register>(),
7114                      method_offset);
7115  } else {
7116    uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
7117        instruction->GetIndex() % ImTable::kSize, kArmPointerSize));
7118    __ LoadFromOffset(kLoadWord,
7119                      locations->Out().AsRegister<Register>(),
7120                      locations->InAt(0).AsRegister<Register>(),
7121                      mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
7122    __ LoadFromOffset(kLoadWord,
7123                      locations->Out().AsRegister<Register>(),
7124                      locations->Out().AsRegister<Register>(),
7125                      method_offset);
7126  }
7127}
7128
7129#undef __
7130#undef QUICK_ENTRY_POINT
7131
7132}  // namespace arm
7133}  // namespace art
7134