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