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