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