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