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