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