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