code_generator_arm.cc revision d09584456559f669f5999fb1ff32aa89ebf6ef4e
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  QuickEntrypointEnum entrypoint =
3997      CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
3998  codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
3999  CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
4000  DCHECK(!codegen_->IsLeafMethod());
4001}
4002
4003void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
4004  LocationSummary* locations =
4005      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4006  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4007  if (location.IsStackSlot()) {
4008    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4009  } else if (location.IsDoubleStackSlot()) {
4010    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4011  }
4012  locations->SetOut(location);
4013}
4014
4015void InstructionCodeGeneratorARM::VisitParameterValue(
4016    HParameterValue* instruction ATTRIBUTE_UNUSED) {
4017  // Nothing to do, the parameter is already at its location.
4018}
4019
4020void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4021  LocationSummary* locations =
4022      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4023  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4024}
4025
4026void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4027  // Nothing to do, the method is already at its location.
4028}
4029
4030void LocationsBuilderARM::VisitNot(HNot* not_) {
4031  LocationSummary* locations =
4032      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
4033  locations->SetInAt(0, Location::RequiresRegister());
4034  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4035}
4036
4037void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4038  LocationSummary* locations = not_->GetLocations();
4039  Location out = locations->Out();
4040  Location in = locations->InAt(0);
4041  switch (not_->GetResultType()) {
4042    case Primitive::kPrimInt:
4043      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
4044      break;
4045
4046    case Primitive::kPrimLong:
4047      __ mvn(out.AsRegisterPairLow<Register>(),
4048             ShifterOperand(in.AsRegisterPairLow<Register>()));
4049      __ mvn(out.AsRegisterPairHigh<Register>(),
4050             ShifterOperand(in.AsRegisterPairHigh<Register>()));
4051      break;
4052
4053    default:
4054      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4055  }
4056}
4057
4058void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4059  LocationSummary* locations =
4060      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4061  locations->SetInAt(0, Location::RequiresRegister());
4062  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4063}
4064
4065void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
4066  LocationSummary* locations = bool_not->GetLocations();
4067  Location out = locations->Out();
4068  Location in = locations->InAt(0);
4069  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4070}
4071
4072void LocationsBuilderARM::VisitCompare(HCompare* compare) {
4073  LocationSummary* locations =
4074      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
4075  switch (compare->InputAt(0)->GetType()) {
4076    case Primitive::kPrimBoolean:
4077    case Primitive::kPrimByte:
4078    case Primitive::kPrimShort:
4079    case Primitive::kPrimChar:
4080    case Primitive::kPrimInt:
4081    case Primitive::kPrimLong: {
4082      locations->SetInAt(0, Location::RequiresRegister());
4083      locations->SetInAt(1, Location::RequiresRegister());
4084      // Output overlaps because it is written before doing the low comparison.
4085      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4086      break;
4087    }
4088    case Primitive::kPrimFloat:
4089    case Primitive::kPrimDouble: {
4090      locations->SetInAt(0, Location::RequiresFpuRegister());
4091      locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
4092      locations->SetOut(Location::RequiresRegister());
4093      break;
4094    }
4095    default:
4096      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4097  }
4098}
4099
4100void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
4101  LocationSummary* locations = compare->GetLocations();
4102  Register out = locations->Out().AsRegister<Register>();
4103  Location left = locations->InAt(0);
4104  Location right = locations->InAt(1);
4105
4106  Label less, greater, done;
4107  Primitive::Type type = compare->InputAt(0)->GetType();
4108  Condition less_cond;
4109  switch (type) {
4110    case Primitive::kPrimBoolean:
4111    case Primitive::kPrimByte:
4112    case Primitive::kPrimShort:
4113    case Primitive::kPrimChar:
4114    case Primitive::kPrimInt: {
4115      __ LoadImmediate(out, 0);
4116      __ cmp(left.AsRegister<Register>(),
4117             ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
4118      less_cond = LT;
4119      break;
4120    }
4121    case Primitive::kPrimLong: {
4122      __ cmp(left.AsRegisterPairHigh<Register>(),
4123             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
4124      __ b(&less, LT);
4125      __ b(&greater, GT);
4126      // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
4127      __ LoadImmediate(out, 0);
4128      __ cmp(left.AsRegisterPairLow<Register>(),
4129             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
4130      less_cond = LO;
4131      break;
4132    }
4133    case Primitive::kPrimFloat:
4134    case Primitive::kPrimDouble: {
4135      __ LoadImmediate(out, 0);
4136      GenerateVcmp(compare);
4137      __ vmstat();  // transfer FP status register to ARM APSR.
4138      less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
4139      break;
4140    }
4141    default:
4142      LOG(FATAL) << "Unexpected compare type " << type;
4143      UNREACHABLE();
4144  }
4145
4146  __ b(&done, EQ);
4147  __ b(&less, less_cond);
4148
4149  __ Bind(&greater);
4150  __ LoadImmediate(out, 1);
4151  __ b(&done);
4152
4153  __ Bind(&less);
4154  __ LoadImmediate(out, -1);
4155
4156  __ Bind(&done);
4157}
4158
4159void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
4160  LocationSummary* locations =
4161      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4162  for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
4163    locations->SetInAt(i, Location::Any());
4164  }
4165  locations->SetOut(Location::Any());
4166}
4167
4168void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
4169  LOG(FATAL) << "Unreachable";
4170}
4171
4172void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
4173  // TODO (ported from quick): revisit ARM barrier kinds.
4174  DmbOptions flavor = DmbOptions::ISH;  // Quiet C++ warnings.
4175  switch (kind) {
4176    case MemBarrierKind::kAnyStore:
4177    case MemBarrierKind::kLoadAny:
4178    case MemBarrierKind::kAnyAny: {
4179      flavor = DmbOptions::ISH;
4180      break;
4181    }
4182    case MemBarrierKind::kStoreStore: {
4183      flavor = DmbOptions::ISHST;
4184      break;
4185    }
4186    default:
4187      LOG(FATAL) << "Unexpected memory barrier " << kind;
4188  }
4189  __ dmb(flavor);
4190}
4191
4192void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
4193                                                         uint32_t offset,
4194                                                         Register out_lo,
4195                                                         Register out_hi) {
4196  if (offset != 0) {
4197    // Ensure `out_lo` is different from `addr`, so that loading
4198    // `offset` into `out_lo` does not clutter `addr`.
4199    DCHECK_NE(out_lo, addr);
4200    __ LoadImmediate(out_lo, offset);
4201    __ add(IP, addr, ShifterOperand(out_lo));
4202    addr = IP;
4203  }
4204  __ ldrexd(out_lo, out_hi, addr);
4205}
4206
4207void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
4208                                                          uint32_t offset,
4209                                                          Register value_lo,
4210                                                          Register value_hi,
4211                                                          Register temp1,
4212                                                          Register temp2,
4213                                                          HInstruction* instruction) {
4214  Label fail;
4215  if (offset != 0) {
4216    __ LoadImmediate(temp1, offset);
4217    __ add(IP, addr, ShifterOperand(temp1));
4218    addr = IP;
4219  }
4220  __ Bind(&fail);
4221  // We need a load followed by store. (The address used in a STREX instruction must
4222  // be the same as the address in the most recently executed LDREX instruction.)
4223  __ ldrexd(temp1, temp2, addr);
4224  codegen_->MaybeRecordImplicitNullCheck(instruction);
4225  __ strexd(temp1, value_lo, value_hi, addr);
4226  __ CompareAndBranchIfNonZero(temp1, &fail);
4227}
4228
4229void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
4230  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4231
4232  LocationSummary* locations =
4233      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4234  locations->SetInAt(0, Location::RequiresRegister());
4235
4236  Primitive::Type field_type = field_info.GetFieldType();
4237  if (Primitive::IsFloatingPointType(field_type)) {
4238    locations->SetInAt(1, Location::RequiresFpuRegister());
4239  } else {
4240    locations->SetInAt(1, Location::RequiresRegister());
4241  }
4242
4243  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
4244  bool generate_volatile = field_info.IsVolatile()
4245      && is_wide
4246      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4247  bool needs_write_barrier =
4248      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
4249  // Temporary registers for the write barrier.
4250  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
4251  if (needs_write_barrier) {
4252    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
4253    locations->AddTemp(Location::RequiresRegister());
4254  } else if (generate_volatile) {
4255    // ARM encoding have some additional constraints for ldrexd/strexd:
4256    // - registers need to be consecutive
4257    // - the first register should be even but not R14.
4258    // We don't test for ARM yet, and the assertion makes sure that we
4259    // revisit this if we ever enable ARM encoding.
4260    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4261
4262    locations->AddTemp(Location::RequiresRegister());
4263    locations->AddTemp(Location::RequiresRegister());
4264    if (field_type == Primitive::kPrimDouble) {
4265      // For doubles we need two more registers to copy the value.
4266      locations->AddTemp(Location::RegisterLocation(R2));
4267      locations->AddTemp(Location::RegisterLocation(R3));
4268    }
4269  }
4270}
4271
4272void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
4273                                                 const FieldInfo& field_info,
4274                                                 bool value_can_be_null) {
4275  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4276
4277  LocationSummary* locations = instruction->GetLocations();
4278  Register base = locations->InAt(0).AsRegister<Register>();
4279  Location value = locations->InAt(1);
4280
4281  bool is_volatile = field_info.IsVolatile();
4282  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4283  Primitive::Type field_type = field_info.GetFieldType();
4284  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4285  bool needs_write_barrier =
4286      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
4287
4288  if (is_volatile) {
4289    codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4290  }
4291
4292  switch (field_type) {
4293    case Primitive::kPrimBoolean:
4294    case Primitive::kPrimByte: {
4295      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
4296      break;
4297    }
4298
4299    case Primitive::kPrimShort:
4300    case Primitive::kPrimChar: {
4301      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
4302      break;
4303    }
4304
4305    case Primitive::kPrimInt:
4306    case Primitive::kPrimNot: {
4307      if (kPoisonHeapReferences && needs_write_barrier) {
4308        // Note that in the case where `value` is a null reference,
4309        // we do not enter this block, as a null reference does not
4310        // need poisoning.
4311        DCHECK_EQ(field_type, Primitive::kPrimNot);
4312        Register temp = locations->GetTemp(0).AsRegister<Register>();
4313        __ Mov(temp, value.AsRegister<Register>());
4314        __ PoisonHeapReference(temp);
4315        __ StoreToOffset(kStoreWord, temp, base, offset);
4316      } else {
4317        __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
4318      }
4319      break;
4320    }
4321
4322    case Primitive::kPrimLong: {
4323      if (is_volatile && !atomic_ldrd_strd) {
4324        GenerateWideAtomicStore(base, offset,
4325                                value.AsRegisterPairLow<Register>(),
4326                                value.AsRegisterPairHigh<Register>(),
4327                                locations->GetTemp(0).AsRegister<Register>(),
4328                                locations->GetTemp(1).AsRegister<Register>(),
4329                                instruction);
4330      } else {
4331        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
4332        codegen_->MaybeRecordImplicitNullCheck(instruction);
4333      }
4334      break;
4335    }
4336
4337    case Primitive::kPrimFloat: {
4338      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
4339      break;
4340    }
4341
4342    case Primitive::kPrimDouble: {
4343      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
4344      if (is_volatile && !atomic_ldrd_strd) {
4345        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
4346        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
4347
4348        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
4349
4350        GenerateWideAtomicStore(base, offset,
4351                                value_reg_lo,
4352                                value_reg_hi,
4353                                locations->GetTemp(2).AsRegister<Register>(),
4354                                locations->GetTemp(3).AsRegister<Register>(),
4355                                instruction);
4356      } else {
4357        __ StoreDToOffset(value_reg, base, offset);
4358        codegen_->MaybeRecordImplicitNullCheck(instruction);
4359      }
4360      break;
4361    }
4362
4363    case Primitive::kPrimVoid:
4364      LOG(FATAL) << "Unreachable type " << field_type;
4365      UNREACHABLE();
4366  }
4367
4368  // Longs and doubles are handled in the switch.
4369  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
4370    codegen_->MaybeRecordImplicitNullCheck(instruction);
4371  }
4372
4373  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
4374    Register temp = locations->GetTemp(0).AsRegister<Register>();
4375    Register card = locations->GetTemp(1).AsRegister<Register>();
4376    codegen_->MarkGCCard(
4377        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
4378  }
4379
4380  if (is_volatile) {
4381    codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4382  }
4383}
4384
4385void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4386  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4387
4388  bool object_field_get_with_read_barrier =
4389      kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
4390  LocationSummary* locations =
4391      new (GetGraph()->GetArena()) LocationSummary(instruction,
4392                                                   object_field_get_with_read_barrier ?
4393                                                       LocationSummary::kCallOnSlowPath :
4394                                                       LocationSummary::kNoCall);
4395  if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4396    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
4397  }
4398  locations->SetInAt(0, Location::RequiresRegister());
4399
4400  bool volatile_for_double = field_info.IsVolatile()
4401      && (field_info.GetFieldType() == Primitive::kPrimDouble)
4402      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4403  // The output overlaps in case of volatile long: we don't want the
4404  // code generated by GenerateWideAtomicLoad to overwrite the
4405  // object's location.  Likewise, in the case of an object field get
4406  // with read barriers enabled, we do not want the load to overwrite
4407  // the object's location, as we need it to emit the read barrier.
4408  bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4409      object_field_get_with_read_barrier;
4410
4411  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4412    locations->SetOut(Location::RequiresFpuRegister());
4413  } else {
4414    locations->SetOut(Location::RequiresRegister(),
4415                      (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4416  }
4417  if (volatile_for_double) {
4418    // ARM encoding have some additional constraints for ldrexd/strexd:
4419    // - registers need to be consecutive
4420    // - the first register should be even but not R14.
4421    // We don't test for ARM yet, and the assertion makes sure that we
4422    // revisit this if we ever enable ARM encoding.
4423    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4424    locations->AddTemp(Location::RequiresRegister());
4425    locations->AddTemp(Location::RequiresRegister());
4426  } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4427    // We need a temporary register for the read barrier marking slow
4428    // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4429    locations->AddTemp(Location::RequiresRegister());
4430  }
4431}
4432
4433Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
4434  DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
4435      << input->GetType();
4436  if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
4437      (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
4438    return Location::ConstantLocation(input->AsConstant());
4439  } else {
4440    return Location::RequiresFpuRegister();
4441  }
4442}
4443
4444Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4445                                                             Opcode opcode) {
4446  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4447  if (constant->IsConstant() &&
4448      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4449    return Location::ConstantLocation(constant->AsConstant());
4450  }
4451  return Location::RequiresRegister();
4452}
4453
4454bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4455                                                       Opcode opcode) {
4456  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4457  if (Primitive::Is64BitType(input_cst->GetType())) {
4458    Opcode high_opcode = opcode;
4459    SetCc low_set_cc = kCcDontCare;
4460    switch (opcode) {
4461      case SUB:
4462        // Flip the operation to an ADD.
4463        value = -value;
4464        opcode = ADD;
4465        FALLTHROUGH_INTENDED;
4466      case ADD:
4467        if (Low32Bits(value) == 0u) {
4468          return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
4469        }
4470        high_opcode = ADC;
4471        low_set_cc = kCcSet;
4472        break;
4473      default:
4474        break;
4475    }
4476    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
4477        CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
4478  } else {
4479    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4480  }
4481}
4482
4483bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
4484                                                       Opcode opcode,
4485                                                       SetCc set_cc) {
4486  ShifterOperand so;
4487  ArmAssembler* assembler = codegen_->GetAssembler();
4488  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
4489    return true;
4490  }
4491  Opcode neg_opcode = kNoOperand;
4492  switch (opcode) {
4493    case AND: neg_opcode = BIC; value = ~value; break;
4494    case ORR: neg_opcode = ORN; value = ~value; break;
4495    case ADD: neg_opcode = SUB; value = -value; break;
4496    case ADC: neg_opcode = SBC; value = ~value; break;
4497    case SUB: neg_opcode = ADD; value = -value; break;
4498    case SBC: neg_opcode = ADC; value = ~value; break;
4499    default:
4500      return false;
4501  }
4502  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, value, set_cc, &so);
4503}
4504
4505void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4506                                                 const FieldInfo& field_info) {
4507  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
4508
4509  LocationSummary* locations = instruction->GetLocations();
4510  Location base_loc = locations->InAt(0);
4511  Register base = base_loc.AsRegister<Register>();
4512  Location out = locations->Out();
4513  bool is_volatile = field_info.IsVolatile();
4514  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
4515  Primitive::Type field_type = field_info.GetFieldType();
4516  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4517
4518  switch (field_type) {
4519    case Primitive::kPrimBoolean:
4520      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
4521      break;
4522
4523    case Primitive::kPrimByte:
4524      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
4525      break;
4526
4527    case Primitive::kPrimShort:
4528      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
4529      break;
4530
4531    case Primitive::kPrimChar:
4532      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
4533      break;
4534
4535    case Primitive::kPrimInt:
4536      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4537      break;
4538
4539    case Primitive::kPrimNot: {
4540      // /* HeapReference<Object> */ out = *(base + offset)
4541      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4542        Location temp_loc = locations->GetTemp(0);
4543        // Note that a potential implicit null check is handled in this
4544        // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4545        codegen_->GenerateFieldLoadWithBakerReadBarrier(
4546            instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4547        if (is_volatile) {
4548          codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4549        }
4550      } else {
4551        __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4552        codegen_->MaybeRecordImplicitNullCheck(instruction);
4553        if (is_volatile) {
4554          codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4555        }
4556        // If read barriers are enabled, emit read barriers other than
4557        // Baker's using a slow path (and also unpoison the loaded
4558        // reference, if heap poisoning is enabled).
4559        codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4560      }
4561      break;
4562    }
4563
4564    case Primitive::kPrimLong:
4565      if (is_volatile && !atomic_ldrd_strd) {
4566        GenerateWideAtomicLoad(base, offset,
4567                               out.AsRegisterPairLow<Register>(),
4568                               out.AsRegisterPairHigh<Register>());
4569      } else {
4570        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4571      }
4572      break;
4573
4574    case Primitive::kPrimFloat:
4575      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
4576      break;
4577
4578    case Primitive::kPrimDouble: {
4579      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
4580      if (is_volatile && !atomic_ldrd_strd) {
4581        Register lo = locations->GetTemp(0).AsRegister<Register>();
4582        Register hi = locations->GetTemp(1).AsRegister<Register>();
4583        GenerateWideAtomicLoad(base, offset, lo, hi);
4584        codegen_->MaybeRecordImplicitNullCheck(instruction);
4585        __ vmovdrr(out_reg, lo, hi);
4586      } else {
4587        __ LoadDFromOffset(out_reg, base, offset);
4588        codegen_->MaybeRecordImplicitNullCheck(instruction);
4589      }
4590      break;
4591    }
4592
4593    case Primitive::kPrimVoid:
4594      LOG(FATAL) << "Unreachable type " << field_type;
4595      UNREACHABLE();
4596  }
4597
4598  if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4599    // Potential implicit null checks, in the case of reference or
4600    // double fields, are handled in the previous switch statement.
4601  } else {
4602    codegen_->MaybeRecordImplicitNullCheck(instruction);
4603  }
4604
4605  if (is_volatile) {
4606    if (field_type == Primitive::kPrimNot) {
4607      // Memory barriers, in the case of references, are also handled
4608      // in the previous switch statement.
4609    } else {
4610      codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4611    }
4612  }
4613}
4614
4615void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4616  HandleFieldSet(instruction, instruction->GetFieldInfo());
4617}
4618
4619void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4620  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4621}
4622
4623void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4624  HandleFieldGet(instruction, instruction->GetFieldInfo());
4625}
4626
4627void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4628  HandleFieldGet(instruction, instruction->GetFieldInfo());
4629}
4630
4631void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4632  HandleFieldGet(instruction, instruction->GetFieldInfo());
4633}
4634
4635void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4636  HandleFieldGet(instruction, instruction->GetFieldInfo());
4637}
4638
4639void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4640  HandleFieldSet(instruction, instruction->GetFieldInfo());
4641}
4642
4643void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4644  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4645}
4646
4647void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4648    HUnresolvedInstanceFieldGet* instruction) {
4649  FieldAccessCallingConventionARM calling_convention;
4650  codegen_->CreateUnresolvedFieldLocationSummary(
4651      instruction, instruction->GetFieldType(), calling_convention);
4652}
4653
4654void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4655    HUnresolvedInstanceFieldGet* instruction) {
4656  FieldAccessCallingConventionARM calling_convention;
4657  codegen_->GenerateUnresolvedFieldAccess(instruction,
4658                                          instruction->GetFieldType(),
4659                                          instruction->GetFieldIndex(),
4660                                          instruction->GetDexPc(),
4661                                          calling_convention);
4662}
4663
4664void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4665    HUnresolvedInstanceFieldSet* instruction) {
4666  FieldAccessCallingConventionARM calling_convention;
4667  codegen_->CreateUnresolvedFieldLocationSummary(
4668      instruction, instruction->GetFieldType(), calling_convention);
4669}
4670
4671void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4672    HUnresolvedInstanceFieldSet* instruction) {
4673  FieldAccessCallingConventionARM calling_convention;
4674  codegen_->GenerateUnresolvedFieldAccess(instruction,
4675                                          instruction->GetFieldType(),
4676                                          instruction->GetFieldIndex(),
4677                                          instruction->GetDexPc(),
4678                                          calling_convention);
4679}
4680
4681void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4682    HUnresolvedStaticFieldGet* instruction) {
4683  FieldAccessCallingConventionARM calling_convention;
4684  codegen_->CreateUnresolvedFieldLocationSummary(
4685      instruction, instruction->GetFieldType(), calling_convention);
4686}
4687
4688void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4689    HUnresolvedStaticFieldGet* instruction) {
4690  FieldAccessCallingConventionARM calling_convention;
4691  codegen_->GenerateUnresolvedFieldAccess(instruction,
4692                                          instruction->GetFieldType(),
4693                                          instruction->GetFieldIndex(),
4694                                          instruction->GetDexPc(),
4695                                          calling_convention);
4696}
4697
4698void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4699    HUnresolvedStaticFieldSet* instruction) {
4700  FieldAccessCallingConventionARM calling_convention;
4701  codegen_->CreateUnresolvedFieldLocationSummary(
4702      instruction, instruction->GetFieldType(), calling_convention);
4703}
4704
4705void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4706    HUnresolvedStaticFieldSet* instruction) {
4707  FieldAccessCallingConventionARM calling_convention;
4708  codegen_->GenerateUnresolvedFieldAccess(instruction,
4709                                          instruction->GetFieldType(),
4710                                          instruction->GetFieldIndex(),
4711                                          instruction->GetDexPc(),
4712                                          calling_convention);
4713}
4714
4715void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
4716  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
4717  locations->SetInAt(0, Location::RequiresRegister());
4718}
4719
4720void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4721  if (CanMoveNullCheckToUser(instruction)) {
4722    return;
4723  }
4724  Location obj = instruction->GetLocations()->InAt(0);
4725
4726  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4727  RecordPcInfo(instruction, instruction->GetDexPc());
4728}
4729
4730void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
4731  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
4732  AddSlowPath(slow_path);
4733
4734  LocationSummary* locations = instruction->GetLocations();
4735  Location obj = locations->InAt(0);
4736
4737  __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
4738}
4739
4740void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
4741  codegen_->GenerateNullCheck(instruction);
4742}
4743
4744static LoadOperandType GetLoadOperandType(Primitive::Type type) {
4745  switch (type) {
4746    case Primitive::kPrimNot:
4747      return kLoadWord;
4748    case Primitive::kPrimBoolean:
4749      return kLoadUnsignedByte;
4750    case Primitive::kPrimByte:
4751      return kLoadSignedByte;
4752    case Primitive::kPrimChar:
4753      return kLoadUnsignedHalfword;
4754    case Primitive::kPrimShort:
4755      return kLoadSignedHalfword;
4756    case Primitive::kPrimInt:
4757      return kLoadWord;
4758    case Primitive::kPrimLong:
4759      return kLoadWordPair;
4760    case Primitive::kPrimFloat:
4761      return kLoadSWord;
4762    case Primitive::kPrimDouble:
4763      return kLoadDWord;
4764    default:
4765      LOG(FATAL) << "Unreachable type " << type;
4766      UNREACHABLE();
4767  }
4768}
4769
4770static StoreOperandType GetStoreOperandType(Primitive::Type type) {
4771  switch (type) {
4772    case Primitive::kPrimNot:
4773      return kStoreWord;
4774    case Primitive::kPrimBoolean:
4775    case Primitive::kPrimByte:
4776      return kStoreByte;
4777    case Primitive::kPrimChar:
4778    case Primitive::kPrimShort:
4779      return kStoreHalfword;
4780    case Primitive::kPrimInt:
4781      return kStoreWord;
4782    case Primitive::kPrimLong:
4783      return kStoreWordPair;
4784    case Primitive::kPrimFloat:
4785      return kStoreSWord;
4786    case Primitive::kPrimDouble:
4787      return kStoreDWord;
4788    default:
4789      LOG(FATAL) << "Unreachable type " << type;
4790      UNREACHABLE();
4791  }
4792}
4793
4794void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
4795                                                Location out_loc,
4796                                                Register base,
4797                                                Register reg_offset,
4798                                                Condition cond) {
4799  uint32_t shift_count = Primitive::ComponentSizeShift(type);
4800  Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4801
4802  switch (type) {
4803    case Primitive::kPrimByte:
4804      __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
4805      break;
4806    case Primitive::kPrimBoolean:
4807      __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
4808      break;
4809    case Primitive::kPrimShort:
4810      __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
4811      break;
4812    case Primitive::kPrimChar:
4813      __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
4814      break;
4815    case Primitive::kPrimNot:
4816    case Primitive::kPrimInt:
4817      __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
4818      break;
4819    // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
4820    case Primitive::kPrimLong:
4821    case Primitive::kPrimFloat:
4822    case Primitive::kPrimDouble:
4823    default:
4824      LOG(FATAL) << "Unreachable type " << type;
4825      UNREACHABLE();
4826  }
4827}
4828
4829void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
4830                                               Location loc,
4831                                               Register base,
4832                                               Register reg_offset,
4833                                               Condition cond) {
4834  uint32_t shift_count = Primitive::ComponentSizeShift(type);
4835  Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4836
4837  switch (type) {
4838    case Primitive::kPrimByte:
4839    case Primitive::kPrimBoolean:
4840      __ strb(loc.AsRegister<Register>(), mem_address, cond);
4841      break;
4842    case Primitive::kPrimShort:
4843    case Primitive::kPrimChar:
4844      __ strh(loc.AsRegister<Register>(), mem_address, cond);
4845      break;
4846    case Primitive::kPrimNot:
4847    case Primitive::kPrimInt:
4848      __ str(loc.AsRegister<Register>(), mem_address, cond);
4849      break;
4850    // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
4851    case Primitive::kPrimLong:
4852    case Primitive::kPrimFloat:
4853    case Primitive::kPrimDouble:
4854    default:
4855      LOG(FATAL) << "Unreachable type " << type;
4856      UNREACHABLE();
4857  }
4858}
4859
4860void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
4861  bool object_array_get_with_read_barrier =
4862      kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
4863  LocationSummary* locations =
4864      new (GetGraph()->GetArena()) LocationSummary(instruction,
4865                                                   object_array_get_with_read_barrier ?
4866                                                       LocationSummary::kCallOnSlowPath :
4867                                                       LocationSummary::kNoCall);
4868  if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4869    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
4870  }
4871  locations->SetInAt(0, Location::RequiresRegister());
4872  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4873  if (Primitive::IsFloatingPointType(instruction->GetType())) {
4874    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4875  } else {
4876    // The output overlaps in the case of an object array get with
4877    // read barriers enabled: we do not want the move to overwrite the
4878    // array's location, as we need it to emit the read barrier.
4879    locations->SetOut(
4880        Location::RequiresRegister(),
4881        object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
4882  }
4883  // We need a temporary register for the read barrier marking slow
4884  // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4885  // Also need for String compression feature.
4886  if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
4887      || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
4888    locations->AddTemp(Location::RequiresRegister());
4889  }
4890}
4891
4892void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4893  LocationSummary* locations = instruction->GetLocations();
4894  Location obj_loc = locations->InAt(0);
4895  Register obj = obj_loc.AsRegister<Register>();
4896  Location index = locations->InAt(1);
4897  Location out_loc = locations->Out();
4898  uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
4899  Primitive::Type type = instruction->GetType();
4900  const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
4901                                        instruction->IsStringCharAt();
4902  HInstruction* array_instr = instruction->GetArray();
4903  bool has_intermediate_address = array_instr->IsIntermediateAddress();
4904
4905  switch (type) {
4906    case Primitive::kPrimBoolean:
4907    case Primitive::kPrimByte:
4908    case Primitive::kPrimShort:
4909    case Primitive::kPrimChar:
4910    case Primitive::kPrimInt: {
4911      Register length;
4912      if (maybe_compressed_char_at) {
4913        length = locations->GetTemp(0).AsRegister<Register>();
4914        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
4915        __ LoadFromOffset(kLoadWord, length, obj, count_offset);
4916        codegen_->MaybeRecordImplicitNullCheck(instruction);
4917      }
4918      if (index.IsConstant()) {
4919        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
4920        if (maybe_compressed_char_at) {
4921          Label uncompressed_load, done;
4922          __ Lsrs(length, length, 1u);  // LSRS has a 16-bit encoding, TST (immediate) does not.
4923          static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4924                        "Expecting 0=compressed, 1=uncompressed");
4925          __ b(&uncompressed_load, CS);
4926          __ LoadFromOffset(kLoadUnsignedByte,
4927                            out_loc.AsRegister<Register>(),
4928                            obj,
4929                            data_offset + const_index);
4930          __ b(&done);
4931          __ Bind(&uncompressed_load);
4932          __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
4933                            out_loc.AsRegister<Register>(),
4934                            obj,
4935                            data_offset + (const_index << 1));
4936          __ Bind(&done);
4937        } else {
4938          uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
4939
4940          LoadOperandType load_type = GetLoadOperandType(type);
4941          __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
4942        }
4943      } else {
4944        Register temp = IP;
4945
4946        if (has_intermediate_address) {
4947          // We do not need to compute the intermediate address from the array: the
4948          // input instruction has done it already. See the comment in
4949          // `TryExtractArrayAccessAddress()`.
4950          if (kIsDebugBuild) {
4951            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4952            DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4953          }
4954          temp = obj;
4955        } else {
4956          __ add(temp, obj, ShifterOperand(data_offset));
4957        }
4958        if (maybe_compressed_char_at) {
4959          Label uncompressed_load, done;
4960          __ Lsrs(length, length, 1u);  // LSRS has a 16-bit encoding, TST (immediate) does not.
4961          static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
4962                        "Expecting 0=compressed, 1=uncompressed");
4963          __ b(&uncompressed_load, CS);
4964          __ ldrb(out_loc.AsRegister<Register>(),
4965                  Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
4966          __ b(&done);
4967          __ Bind(&uncompressed_load);
4968          __ ldrh(out_loc.AsRegister<Register>(),
4969                  Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
4970          __ Bind(&done);
4971        } else {
4972          codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
4973        }
4974      }
4975      break;
4976    }
4977
4978    case Primitive::kPrimNot: {
4979      // The read barrier instrumentation of object ArrayGet
4980      // instructions does not support the HIntermediateAddress
4981      // instruction.
4982      DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
4983
4984      static_assert(
4985          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4986          "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4987      // /* HeapReference<Object> */ out =
4988      //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
4989      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4990        Location temp = locations->GetTemp(0);
4991        // Note that a potential implicit null check is handled in this
4992        // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4993        codegen_->GenerateArrayLoadWithBakerReadBarrier(
4994            instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4995      } else {
4996        Register out = out_loc.AsRegister<Register>();
4997        if (index.IsConstant()) {
4998          size_t offset =
4999              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5000          __ LoadFromOffset(kLoadWord, out, obj, offset);
5001          codegen_->MaybeRecordImplicitNullCheck(instruction);
5002          // If read barriers are enabled, emit read barriers other than
5003          // Baker's using a slow path (and also unpoison the loaded
5004          // reference, if heap poisoning is enabled).
5005          codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5006        } else {
5007          Register temp = IP;
5008
5009          if (has_intermediate_address) {
5010            // We do not need to compute the intermediate address from the array: the
5011            // input instruction has done it already. See the comment in
5012            // `TryExtractArrayAccessAddress()`.
5013            if (kIsDebugBuild) {
5014              HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5015              DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5016            }
5017            temp = obj;
5018          } else {
5019            __ add(temp, obj, ShifterOperand(data_offset));
5020          }
5021          codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
5022
5023          codegen_->MaybeRecordImplicitNullCheck(instruction);
5024          // If read barriers are enabled, emit read barriers other than
5025          // Baker's using a slow path (and also unpoison the loaded
5026          // reference, if heap poisoning is enabled).
5027          codegen_->MaybeGenerateReadBarrierSlow(
5028              instruction, out_loc, out_loc, obj_loc, data_offset, index);
5029        }
5030      }
5031      break;
5032    }
5033
5034    case Primitive::kPrimLong: {
5035      if (index.IsConstant()) {
5036        size_t offset =
5037            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5038        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
5039      } else {
5040        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5041        __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
5042      }
5043      break;
5044    }
5045
5046    case Primitive::kPrimFloat: {
5047      SRegister out = out_loc.AsFpuRegister<SRegister>();
5048      if (index.IsConstant()) {
5049        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5050        __ LoadSFromOffset(out, obj, offset);
5051      } else {
5052        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
5053        __ LoadSFromOffset(out, IP, data_offset);
5054      }
5055      break;
5056    }
5057
5058    case Primitive::kPrimDouble: {
5059      SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
5060      if (index.IsConstant()) {
5061        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5062        __ LoadDFromOffset(FromLowSToD(out), obj, offset);
5063      } else {
5064        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5065        __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
5066      }
5067      break;
5068    }
5069
5070    case Primitive::kPrimVoid:
5071      LOG(FATAL) << "Unreachable type " << type;
5072      UNREACHABLE();
5073  }
5074
5075  if (type == Primitive::kPrimNot) {
5076    // Potential implicit null checks, in the case of reference
5077    // arrays, are handled in the previous switch statement.
5078  } else if (!maybe_compressed_char_at) {
5079    codegen_->MaybeRecordImplicitNullCheck(instruction);
5080  }
5081}
5082
5083void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
5084  Primitive::Type value_type = instruction->GetComponentType();
5085
5086  bool needs_write_barrier =
5087      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
5088  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
5089
5090  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
5091      instruction,
5092      may_need_runtime_call_for_type_check ?
5093          LocationSummary::kCallOnSlowPath :
5094          LocationSummary::kNoCall);
5095
5096  locations->SetInAt(0, Location::RequiresRegister());
5097  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5098  if (Primitive::IsFloatingPointType(value_type)) {
5099    locations->SetInAt(2, Location::RequiresFpuRegister());
5100  } else {
5101    locations->SetInAt(2, Location::RequiresRegister());
5102  }
5103  if (needs_write_barrier) {
5104    // Temporary registers for the write barrier.
5105    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
5106    locations->AddTemp(Location::RequiresRegister());
5107  }
5108}
5109
5110void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
5111  LocationSummary* locations = instruction->GetLocations();
5112  Location array_loc = locations->InAt(0);
5113  Register array = array_loc.AsRegister<Register>();
5114  Location index = locations->InAt(1);
5115  Primitive::Type value_type = instruction->GetComponentType();
5116  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
5117  bool needs_write_barrier =
5118      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
5119  uint32_t data_offset =
5120      mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
5121  Location value_loc = locations->InAt(2);
5122  HInstruction* array_instr = instruction->GetArray();
5123  bool has_intermediate_address = array_instr->IsIntermediateAddress();
5124
5125  switch (value_type) {
5126    case Primitive::kPrimBoolean:
5127    case Primitive::kPrimByte:
5128    case Primitive::kPrimShort:
5129    case Primitive::kPrimChar:
5130    case Primitive::kPrimInt: {
5131      if (index.IsConstant()) {
5132        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
5133        uint32_t full_offset =
5134            data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
5135        StoreOperandType store_type = GetStoreOperandType(value_type);
5136        __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
5137      } else {
5138        Register temp = IP;
5139
5140        if (has_intermediate_address) {
5141          // We do not need to compute the intermediate address from the array: the
5142          // input instruction has done it already. See the comment in
5143          // `TryExtractArrayAccessAddress()`.
5144          if (kIsDebugBuild) {
5145            HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5146            DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
5147          }
5148          temp = array;
5149        } else {
5150          __ add(temp, array, ShifterOperand(data_offset));
5151        }
5152        codegen_->StoreToShiftedRegOffset(value_type,
5153                                          value_loc,
5154                                          temp,
5155                                          index.AsRegister<Register>());
5156      }
5157      break;
5158    }
5159
5160    case Primitive::kPrimNot: {
5161      Register value = value_loc.AsRegister<Register>();
5162      // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
5163      // See the comment in instruction_simplifier_shared.cc.
5164      DCHECK(!has_intermediate_address);
5165
5166      if (instruction->InputAt(2)->IsNullConstant()) {
5167        // Just setting null.
5168        if (index.IsConstant()) {
5169          size_t offset =
5170              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5171          __ StoreToOffset(kStoreWord, value, array, offset);
5172        } else {
5173          DCHECK(index.IsRegister()) << index;
5174          __ add(IP, array, ShifterOperand(data_offset));
5175          codegen_->StoreToShiftedRegOffset(value_type,
5176                                            value_loc,
5177                                            IP,
5178                                            index.AsRegister<Register>());
5179        }
5180        codegen_->MaybeRecordImplicitNullCheck(instruction);
5181        DCHECK(!needs_write_barrier);
5182        DCHECK(!may_need_runtime_call_for_type_check);
5183        break;
5184      }
5185
5186      DCHECK(needs_write_barrier);
5187      Location temp1_loc = locations->GetTemp(0);
5188      Register temp1 = temp1_loc.AsRegister<Register>();
5189      Location temp2_loc = locations->GetTemp(1);
5190      Register temp2 = temp2_loc.AsRegister<Register>();
5191      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5192      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5193      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5194      Label done;
5195      SlowPathCodeARM* slow_path = nullptr;
5196
5197      if (may_need_runtime_call_for_type_check) {
5198        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
5199        codegen_->AddSlowPath(slow_path);
5200        if (instruction->GetValueCanBeNull()) {
5201          Label non_zero;
5202          __ CompareAndBranchIfNonZero(value, &non_zero);
5203          if (index.IsConstant()) {
5204            size_t offset =
5205               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5206            __ StoreToOffset(kStoreWord, value, array, offset);
5207          } else {
5208            DCHECK(index.IsRegister()) << index;
5209            __ add(IP, array, ShifterOperand(data_offset));
5210            codegen_->StoreToShiftedRegOffset(value_type,
5211                                              value_loc,
5212                                              IP,
5213                                              index.AsRegister<Register>());
5214          }
5215          codegen_->MaybeRecordImplicitNullCheck(instruction);
5216          __ b(&done);
5217          __ Bind(&non_zero);
5218        }
5219
5220        // Note that when read barriers are enabled, the type checks
5221        // are performed without read barriers.  This is fine, even in
5222        // the case where a class object is in the from-space after
5223        // the flip, as a comparison involving such a type would not
5224        // produce a false positive; it may of course produce a false
5225        // negative, in which case we would take the ArraySet slow
5226        // path.
5227
5228        // /* HeapReference<Class> */ temp1 = array->klass_
5229        __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
5230        codegen_->MaybeRecordImplicitNullCheck(instruction);
5231        __ MaybeUnpoisonHeapReference(temp1);
5232
5233        // /* HeapReference<Class> */ temp1 = temp1->component_type_
5234        __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
5235        // /* HeapReference<Class> */ temp2 = value->klass_
5236        __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
5237        // If heap poisoning is enabled, no need to unpoison `temp1`
5238        // nor `temp2`, as we are comparing two poisoned references.
5239        __ cmp(temp1, ShifterOperand(temp2));
5240
5241        if (instruction->StaticTypeOfArrayIsObjectArray()) {
5242          Label do_put;
5243          __ b(&do_put, EQ);
5244          // If heap poisoning is enabled, the `temp1` reference has
5245          // not been unpoisoned yet; unpoison it now.
5246          __ MaybeUnpoisonHeapReference(temp1);
5247
5248          // /* HeapReference<Class> */ temp1 = temp1->super_class_
5249          __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
5250          // If heap poisoning is enabled, no need to unpoison
5251          // `temp1`, as we are comparing against null below.
5252          __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
5253          __ Bind(&do_put);
5254        } else {
5255          __ b(slow_path->GetEntryLabel(), NE);
5256        }
5257      }
5258
5259      Register source = value;
5260      if (kPoisonHeapReferences) {
5261        // Note that in the case where `value` is a null reference,
5262        // we do not enter this block, as a null reference does not
5263        // need poisoning.
5264        DCHECK_EQ(value_type, Primitive::kPrimNot);
5265        __ Mov(temp1, value);
5266        __ PoisonHeapReference(temp1);
5267        source = temp1;
5268      }
5269
5270      if (index.IsConstant()) {
5271        size_t offset =
5272            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5273        __ StoreToOffset(kStoreWord, source, array, offset);
5274      } else {
5275        DCHECK(index.IsRegister()) << index;
5276
5277        __ add(IP, array, ShifterOperand(data_offset));
5278        codegen_->StoreToShiftedRegOffset(value_type,
5279                                          Location::RegisterLocation(source),
5280                                          IP,
5281                                          index.AsRegister<Register>());
5282      }
5283
5284      if (!may_need_runtime_call_for_type_check) {
5285        codegen_->MaybeRecordImplicitNullCheck(instruction);
5286      }
5287
5288      codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
5289
5290      if (done.IsLinked()) {
5291        __ Bind(&done);
5292      }
5293
5294      if (slow_path != nullptr) {
5295        __ Bind(slow_path->GetExitLabel());
5296      }
5297
5298      break;
5299    }
5300
5301    case Primitive::kPrimLong: {
5302      Location value = locations->InAt(2);
5303      if (index.IsConstant()) {
5304        size_t offset =
5305            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5306        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
5307      } else {
5308        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5309        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
5310      }
5311      break;
5312    }
5313
5314    case Primitive::kPrimFloat: {
5315      Location value = locations->InAt(2);
5316      DCHECK(value.IsFpuRegister());
5317      if (index.IsConstant()) {
5318        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5319        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
5320      } else {
5321        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
5322        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
5323      }
5324      break;
5325    }
5326
5327    case Primitive::kPrimDouble: {
5328      Location value = locations->InAt(2);
5329      DCHECK(value.IsFpuRegisterPair());
5330      if (index.IsConstant()) {
5331        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
5332        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
5333      } else {
5334        __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
5335        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
5336      }
5337
5338      break;
5339    }
5340
5341    case Primitive::kPrimVoid:
5342      LOG(FATAL) << "Unreachable type " << value_type;
5343      UNREACHABLE();
5344  }
5345
5346  // Objects are handled in the switch.
5347  if (value_type != Primitive::kPrimNot) {
5348    codegen_->MaybeRecordImplicitNullCheck(instruction);
5349  }
5350}
5351
5352void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
5353  LocationSummary* locations =
5354      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5355  locations->SetInAt(0, Location::RequiresRegister());
5356  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5357}
5358
5359void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
5360  LocationSummary* locations = instruction->GetLocations();
5361  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
5362  Register obj = locations->InAt(0).AsRegister<Register>();
5363  Register out = locations->Out().AsRegister<Register>();
5364  __ LoadFromOffset(kLoadWord, out, obj, offset);
5365  codegen_->MaybeRecordImplicitNullCheck(instruction);
5366  // Mask out compression flag from String's array length.
5367  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
5368    __ Lsr(out, out, 1u);
5369  }
5370}
5371
5372void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
5373  LocationSummary* locations =
5374      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5375
5376  locations->SetInAt(0, Location::RequiresRegister());
5377  locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
5378  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5379}
5380
5381void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
5382  LocationSummary* locations = instruction->GetLocations();
5383  Location out = locations->Out();
5384  Location first = locations->InAt(0);
5385  Location second = locations->InAt(1);
5386
5387  if (second.IsRegister()) {
5388    __ add(out.AsRegister<Register>(),
5389           first.AsRegister<Register>(),
5390           ShifterOperand(second.AsRegister<Register>()));
5391  } else {
5392    __ AddConstant(out.AsRegister<Register>(),
5393                   first.AsRegister<Register>(),
5394                   second.GetConstant()->AsIntConstant()->GetValue());
5395  }
5396}
5397
5398void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
5399  RegisterSet caller_saves = RegisterSet::Empty();
5400  InvokeRuntimeCallingConvention calling_convention;
5401  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5402  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5403  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
5404  locations->SetInAt(0, Location::RequiresRegister());
5405  locations->SetInAt(1, Location::RequiresRegister());
5406}
5407
5408void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
5409  LocationSummary* locations = instruction->GetLocations();
5410  SlowPathCodeARM* slow_path =
5411      new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
5412  codegen_->AddSlowPath(slow_path);
5413
5414  Register index = locations->InAt(0).AsRegister<Register>();
5415  Register length = locations->InAt(1).AsRegister<Register>();
5416
5417  __ cmp(index, ShifterOperand(length));
5418  __ b(slow_path->GetEntryLabel(), HS);
5419}
5420
5421void CodeGeneratorARM::MarkGCCard(Register temp,
5422                                  Register card,
5423                                  Register object,
5424                                  Register value,
5425                                  bool can_be_null) {
5426  Label is_null;
5427  if (can_be_null) {
5428    __ CompareAndBranchIfZero(value, &is_null);
5429  }
5430  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
5431  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
5432  __ strb(card, Address(card, temp));
5433  if (can_be_null) {
5434    __ Bind(&is_null);
5435  }
5436}
5437
5438void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
5439  LOG(FATAL) << "Unreachable";
5440}
5441
5442void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
5443  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5444}
5445
5446void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
5447  LocationSummary* locations =
5448      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
5449  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
5450}
5451
5452void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
5453  HBasicBlock* block = instruction->GetBlock();
5454  if (block->GetLoopInformation() != nullptr) {
5455    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5456    // The back edge will generate the suspend check.
5457    return;
5458  }
5459  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5460    // The goto will generate the suspend check.
5461    return;
5462  }
5463  GenerateSuspendCheck(instruction, nullptr);
5464}
5465
5466void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
5467                                                       HBasicBlock* successor) {
5468  SuspendCheckSlowPathARM* slow_path =
5469      down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
5470  if (slow_path == nullptr) {
5471    slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
5472    instruction->SetSlowPath(slow_path);
5473    codegen_->AddSlowPath(slow_path);
5474    if (successor != nullptr) {
5475      DCHECK(successor->IsLoopHeader());
5476      codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5477    }
5478  } else {
5479    DCHECK_EQ(slow_path->GetSuccessor(), successor);
5480  }
5481
5482  __ LoadFromOffset(
5483      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
5484  if (successor == nullptr) {
5485    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
5486    __ Bind(slow_path->GetReturnLabel());
5487  } else {
5488    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
5489    __ b(slow_path->GetEntryLabel());
5490  }
5491}
5492
5493ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
5494  return codegen_->GetAssembler();
5495}
5496
5497void ParallelMoveResolverARM::EmitMove(size_t index) {
5498  MoveOperands* move = moves_[index];
5499  Location source = move->GetSource();
5500  Location destination = move->GetDestination();
5501
5502  if (source.IsRegister()) {
5503    if (destination.IsRegister()) {
5504      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
5505    } else if (destination.IsFpuRegister()) {
5506      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
5507    } else {
5508      DCHECK(destination.IsStackSlot());
5509      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
5510                       SP, destination.GetStackIndex());
5511    }
5512  } else if (source.IsStackSlot()) {
5513    if (destination.IsRegister()) {
5514      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
5515                        SP, source.GetStackIndex());
5516    } else if (destination.IsFpuRegister()) {
5517      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
5518    } else {
5519      DCHECK(destination.IsStackSlot());
5520      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
5521      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5522    }
5523  } else if (source.IsFpuRegister()) {
5524    if (destination.IsRegister()) {
5525      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
5526    } else if (destination.IsFpuRegister()) {
5527      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
5528    } else {
5529      DCHECK(destination.IsStackSlot());
5530      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
5531    }
5532  } else if (source.IsDoubleStackSlot()) {
5533    if (destination.IsDoubleStackSlot()) {
5534      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
5535      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
5536    } else if (destination.IsRegisterPair()) {
5537      DCHECK(ExpectedPairLayout(destination));
5538      __ LoadFromOffset(
5539          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
5540    } else {
5541      DCHECK(destination.IsFpuRegisterPair()) << destination;
5542      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5543                         SP,
5544                         source.GetStackIndex());
5545    }
5546  } else if (source.IsRegisterPair()) {
5547    if (destination.IsRegisterPair()) {
5548      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
5549      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
5550    } else if (destination.IsFpuRegisterPair()) {
5551      __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5552                 source.AsRegisterPairLow<Register>(),
5553                 source.AsRegisterPairHigh<Register>());
5554    } else {
5555      DCHECK(destination.IsDoubleStackSlot()) << destination;
5556      DCHECK(ExpectedPairLayout(source));
5557      __ StoreToOffset(
5558          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
5559    }
5560  } else if (source.IsFpuRegisterPair()) {
5561    if (destination.IsRegisterPair()) {
5562      __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5563                 destination.AsRegisterPairHigh<Register>(),
5564                 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5565    } else if (destination.IsFpuRegisterPair()) {
5566      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5567               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5568    } else {
5569      DCHECK(destination.IsDoubleStackSlot()) << destination;
5570      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
5571                        SP,
5572                        destination.GetStackIndex());
5573    }
5574  } else {
5575    DCHECK(source.IsConstant()) << source;
5576    HConstant* constant = source.GetConstant();
5577    if (constant->IsIntConstant() || constant->IsNullConstant()) {
5578      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
5579      if (destination.IsRegister()) {
5580        __ LoadImmediate(destination.AsRegister<Register>(), value);
5581      } else {
5582        DCHECK(destination.IsStackSlot());
5583        __ LoadImmediate(IP, value);
5584        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5585      }
5586    } else if (constant->IsLongConstant()) {
5587      int64_t value = constant->AsLongConstant()->GetValue();
5588      if (destination.IsRegisterPair()) {
5589        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5590        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
5591      } else {
5592        DCHECK(destination.IsDoubleStackSlot()) << destination;
5593        __ LoadImmediate(IP, Low32Bits(value));
5594        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5595        __ LoadImmediate(IP, High32Bits(value));
5596        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5597      }
5598    } else if (constant->IsDoubleConstant()) {
5599      double value = constant->AsDoubleConstant()->GetValue();
5600      if (destination.IsFpuRegisterPair()) {
5601        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
5602      } else {
5603        DCHECK(destination.IsDoubleStackSlot()) << destination;
5604        uint64_t int_value = bit_cast<uint64_t, double>(value);
5605        __ LoadImmediate(IP, Low32Bits(int_value));
5606        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5607        __ LoadImmediate(IP, High32Bits(int_value));
5608        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5609      }
5610    } else {
5611      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
5612      float value = constant->AsFloatConstant()->GetValue();
5613      if (destination.IsFpuRegister()) {
5614        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5615      } else {
5616        DCHECK(destination.IsStackSlot());
5617        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5618        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5619      }
5620    }
5621  }
5622}
5623
5624void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5625  __ Mov(IP, reg);
5626  __ LoadFromOffset(kLoadWord, reg, SP, mem);
5627  __ StoreToOffset(kStoreWord, IP, SP, mem);
5628}
5629
5630void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5631  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5632  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5633  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5634                    SP, mem1 + stack_offset);
5635  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5636  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5637                   SP, mem2 + stack_offset);
5638  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5639}
5640
5641void ParallelMoveResolverARM::EmitSwap(size_t index) {
5642  MoveOperands* move = moves_[index];
5643  Location source = move->GetSource();
5644  Location destination = move->GetDestination();
5645
5646  if (source.IsRegister() && destination.IsRegister()) {
5647    DCHECK_NE(source.AsRegister<Register>(), IP);
5648    DCHECK_NE(destination.AsRegister<Register>(), IP);
5649    __ Mov(IP, source.AsRegister<Register>());
5650    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5651    __ Mov(destination.AsRegister<Register>(), IP);
5652  } else if (source.IsRegister() && destination.IsStackSlot()) {
5653    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
5654  } else if (source.IsStackSlot() && destination.IsRegister()) {
5655    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
5656  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5657    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5658  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
5659    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
5660    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
5661    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
5662  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
5663    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
5664    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
5665    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
5666    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5667               destination.AsRegisterPairHigh<Register>(),
5668               DTMP);
5669  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
5670    Register low_reg = source.IsRegisterPair()
5671        ? source.AsRegisterPairLow<Register>()
5672        : destination.AsRegisterPairLow<Register>();
5673    int mem = source.IsRegisterPair()
5674        ? destination.GetStackIndex()
5675        : source.GetStackIndex();
5676    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
5677    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
5678    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
5679    __ StoreDToOffset(DTMP, SP, mem);
5680  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
5681    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5682    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5683    __ vmovd(DTMP, first);
5684    __ vmovd(first, second);
5685    __ vmovd(second, DTMP);
5686  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5687    DRegister reg = source.IsFpuRegisterPair()
5688        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5689        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5690    int mem = source.IsFpuRegisterPair()
5691        ? destination.GetStackIndex()
5692        : source.GetStackIndex();
5693    __ vmovd(DTMP, reg);
5694    __ LoadDFromOffset(reg, SP, mem);
5695    __ StoreDToOffset(DTMP, SP, mem);
5696  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5697    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5698                                           : destination.AsFpuRegister<SRegister>();
5699    int mem = source.IsFpuRegister()
5700        ? destination.GetStackIndex()
5701        : source.GetStackIndex();
5702
5703    __ vmovrs(IP, reg);
5704    __ LoadSFromOffset(reg, SP, mem);
5705    __ StoreToOffset(kStoreWord, IP, SP, mem);
5706  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
5707    Exchange(source.GetStackIndex(), destination.GetStackIndex());
5708    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
5709  } else {
5710    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
5711  }
5712}
5713
5714void ParallelMoveResolverARM::SpillScratch(int reg) {
5715  __ Push(static_cast<Register>(reg));
5716}
5717
5718void ParallelMoveResolverARM::RestoreScratch(int reg) {
5719  __ Pop(static_cast<Register>(reg));
5720}
5721
5722HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5723    HLoadClass::LoadKind desired_class_load_kind) {
5724  switch (desired_class_load_kind) {
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      LOG(FATAL) << "UNREACHABLE";
5856      UNREACHABLE();
5857  }
5858
5859  if (generate_null_check || cls->MustGenerateClinitCheck()) {
5860    DCHECK(cls->CanCallRuntime());
5861    SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5862        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5863    codegen_->AddSlowPath(slow_path);
5864    if (generate_null_check) {
5865      __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5866    }
5867    if (cls->MustGenerateClinitCheck()) {
5868      GenerateClassInitializationCheck(slow_path, out);
5869    } else {
5870      __ Bind(slow_path->GetExitLabel());
5871    }
5872  }
5873}
5874
5875void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5876  LocationSummary* locations =
5877      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5878  locations->SetInAt(0, Location::RequiresRegister());
5879  if (check->HasUses()) {
5880    locations->SetOut(Location::SameAsFirstInput());
5881  }
5882}
5883
5884void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
5885  // We assume the class is not null.
5886  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5887      check->GetLoadClass(), check, check->GetDexPc(), true);
5888  codegen_->AddSlowPath(slow_path);
5889  GenerateClassInitializationCheck(slow_path,
5890                                   check->GetLocations()->InAt(0).AsRegister<Register>());
5891}
5892
5893void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
5894    SlowPathCodeARM* slow_path, Register class_reg) {
5895  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5896  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5897  __ b(slow_path->GetEntryLabel(), LT);
5898  // Even if the initialized flag is set, we may be in a situation where caches are not synced
5899  // properly. Therefore, we do a memory fence.
5900  __ dmb(ISH);
5901  __ Bind(slow_path->GetExitLabel());
5902}
5903
5904HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5905    HLoadString::LoadKind desired_string_load_kind) {
5906  switch (desired_string_load_kind) {
5907    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5908      DCHECK(!GetCompilerOptions().GetCompilePic());
5909      break;
5910    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5911      DCHECK(GetCompilerOptions().GetCompilePic());
5912      break;
5913    case HLoadString::LoadKind::kBootImageAddress:
5914      break;
5915    case HLoadString::LoadKind::kBssEntry:
5916      DCHECK(!Runtime::Current()->UseJitCompilation());
5917      break;
5918    case HLoadString::LoadKind::kJitTableAddress:
5919      DCHECK(Runtime::Current()->UseJitCompilation());
5920      break;
5921    case HLoadString::LoadKind::kDexCacheViaMethod:
5922      break;
5923  }
5924  return desired_string_load_kind;
5925}
5926
5927void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5928  LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
5929  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5930  HLoadString::LoadKind load_kind = load->GetLoadKind();
5931  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
5932    locations->SetOut(Location::RegisterLocation(R0));
5933  } else {
5934    locations->SetOut(Location::RequiresRegister());
5935    if (load_kind == HLoadString::LoadKind::kBssEntry) {
5936      if (!kUseReadBarrier || kUseBakerReadBarrier) {
5937        // Rely on the pResolveString and/or marking to save everything, including temps.
5938        // Note that IP may theoretically be clobbered by saving/restoring the live register
5939        // (only one thanks to the custom calling convention), so we request a different temp.
5940        locations->AddTemp(Location::RequiresRegister());
5941        RegisterSet caller_saves = RegisterSet::Empty();
5942        InvokeRuntimeCallingConvention calling_convention;
5943        caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5944        // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
5945        // that the the kPrimNot result register is the same as the first argument register.
5946        locations->SetCustomSlowPathCallerSaves(caller_saves);
5947      } else {
5948        // For non-Baker read barrier we have a temp-clobbering call.
5949      }
5950    }
5951  }
5952}
5953
5954// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5955// move.
5956void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
5957  LocationSummary* locations = load->GetLocations();
5958  Location out_loc = locations->Out();
5959  Register out = out_loc.AsRegister<Register>();
5960  HLoadString::LoadKind load_kind = load->GetLoadKind();
5961
5962  switch (load_kind) {
5963    case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5964      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5965      __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5966                                                                      load->GetStringIndex()));
5967      return;  // No dex cache slow path.
5968    }
5969    case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5970      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5971      CodeGeneratorARM::PcRelativePatchInfo* labels =
5972          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5973      __ BindTrackedLabel(&labels->movw_label);
5974      __ movw(out, /* placeholder */ 0u);
5975      __ BindTrackedLabel(&labels->movt_label);
5976      __ movt(out, /* placeholder */ 0u);
5977      __ BindTrackedLabel(&labels->add_pc_label);
5978      __ add(out, out, ShifterOperand(PC));
5979      return;  // No dex cache slow path.
5980    }
5981    case HLoadString::LoadKind::kBootImageAddress: {
5982      uint32_t address = dchecked_integral_cast<uint32_t>(
5983          reinterpret_cast<uintptr_t>(load->GetString().Get()));
5984      DCHECK_NE(address, 0u);
5985      __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5986      return;  // No dex cache slow path.
5987    }
5988    case HLoadString::LoadKind::kBssEntry: {
5989      DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5990      Register temp = locations->GetTemp(0).AsRegister<Register>();
5991      CodeGeneratorARM::PcRelativePatchInfo* labels =
5992          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5993      __ BindTrackedLabel(&labels->movw_label);
5994      __ movw(temp, /* placeholder */ 0u);
5995      __ BindTrackedLabel(&labels->movt_label);
5996      __ movt(temp, /* placeholder */ 0u);
5997      __ BindTrackedLabel(&labels->add_pc_label);
5998      __ add(temp, temp, ShifterOperand(PC));
5999      GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
6000      SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
6001      codegen_->AddSlowPath(slow_path);
6002      __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6003      __ Bind(slow_path->GetExitLabel());
6004      return;
6005    }
6006    case HLoadString::LoadKind::kJitTableAddress: {
6007      __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
6008                                                                load->GetStringIndex(),
6009                                                                load->GetString()));
6010      // /* GcRoot<mirror::String> */ out = *out
6011      GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
6012      return;
6013    }
6014    default:
6015      break;
6016  }
6017
6018  // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
6019  DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
6020  InvokeRuntimeCallingConvention calling_convention;
6021  DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
6022  __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
6023  codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6024  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
6025}
6026
6027static int32_t GetExceptionTlsOffset() {
6028  return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
6029}
6030
6031void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
6032  LocationSummary* locations =
6033      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
6034  locations->SetOut(Location::RequiresRegister());
6035}
6036
6037void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
6038  Register out = load->GetLocations()->Out().AsRegister<Register>();
6039  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
6040}
6041
6042void LocationsBuilderARM::VisitClearException(HClearException* clear) {
6043  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
6044}
6045
6046void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
6047  __ LoadImmediate(IP, 0);
6048  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
6049}
6050
6051void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
6052  LocationSummary* locations =
6053      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
6054  InvokeRuntimeCallingConvention calling_convention;
6055  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6056}
6057
6058void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
6059  codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
6060  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
6061}
6062
6063// Temp is used for read barrier.
6064static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
6065  if (kEmitCompilerReadBarrier &&
6066       (kUseBakerReadBarrier ||
6067          type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6068          type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6069          type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
6070    return 1;
6071  }
6072  return 0;
6073}
6074
6075// Interface case has 3 temps, one for holding the number of interfaces, one for the current
6076// interface pointer, one for loading the current interface.
6077// The other checks have one temp for loading the object's class.
6078static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
6079  if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
6080    return 3;
6081  }
6082  return 1 + NumberOfInstanceOfTemps(type_check_kind);
6083}
6084
6085void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
6086  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
6087  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6088  bool baker_read_barrier_slow_path = false;
6089  switch (type_check_kind) {
6090    case TypeCheckKind::kExactCheck:
6091    case TypeCheckKind::kAbstractClassCheck:
6092    case TypeCheckKind::kClassHierarchyCheck:
6093    case TypeCheckKind::kArrayObjectCheck:
6094      call_kind =
6095          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
6096      baker_read_barrier_slow_path = kUseBakerReadBarrier;
6097      break;
6098    case TypeCheckKind::kArrayCheck:
6099    case TypeCheckKind::kUnresolvedCheck:
6100    case TypeCheckKind::kInterfaceCheck:
6101      call_kind = LocationSummary::kCallOnSlowPath;
6102      break;
6103  }
6104
6105  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6106  if (baker_read_barrier_slow_path) {
6107    locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
6108  }
6109  locations->SetInAt(0, Location::RequiresRegister());
6110  locations->SetInAt(1, Location::RequiresRegister());
6111  // The "out" register is used as a temporary, so it overlaps with the inputs.
6112  // Note that TypeCheckSlowPathARM uses this register too.
6113  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
6114  locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
6115}
6116
6117void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
6118  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6119  LocationSummary* locations = instruction->GetLocations();
6120  Location obj_loc = locations->InAt(0);
6121  Register obj = obj_loc.AsRegister<Register>();
6122  Register cls = locations->InAt(1).AsRegister<Register>();
6123  Location out_loc = locations->Out();
6124  Register out = out_loc.AsRegister<Register>();
6125  const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
6126  DCHECK_LE(num_temps, 1u);
6127  Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
6128  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6129  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6130  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6131  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6132  Label done, zero;
6133  SlowPathCodeARM* slow_path = nullptr;
6134
6135  // Return 0 if `obj` is null.
6136  // avoid null check if we know obj is not null.
6137  if (instruction->MustDoNullCheck()) {
6138    __ CompareAndBranchIfZero(obj, &zero);
6139  }
6140
6141  switch (type_check_kind) {
6142    case TypeCheckKind::kExactCheck: {
6143      // /* HeapReference<Class> */ out = obj->klass_
6144      GenerateReferenceLoadTwoRegisters(instruction,
6145                                        out_loc,
6146                                        obj_loc,
6147                                        class_offset,
6148                                        maybe_temp_loc,
6149                                        kCompilerReadBarrierOption);
6150      __ cmp(out, ShifterOperand(cls));
6151      // Classes must be equal for the instanceof to succeed.
6152      __ b(&zero, NE);
6153      __ LoadImmediate(out, 1);
6154      __ b(&done);
6155      break;
6156    }
6157
6158    case TypeCheckKind::kAbstractClassCheck: {
6159      // /* HeapReference<Class> */ out = obj->klass_
6160      GenerateReferenceLoadTwoRegisters(instruction,
6161                                        out_loc,
6162                                        obj_loc,
6163                                        class_offset,
6164                                        maybe_temp_loc,
6165                                        kCompilerReadBarrierOption);
6166      // If the class is abstract, we eagerly fetch the super class of the
6167      // object to avoid doing a comparison we know will fail.
6168      Label loop;
6169      __ Bind(&loop);
6170      // /* HeapReference<Class> */ out = out->super_class_
6171      GenerateReferenceLoadOneRegister(instruction,
6172                                       out_loc,
6173                                       super_offset,
6174                                       maybe_temp_loc,
6175                                       kCompilerReadBarrierOption);
6176      // If `out` is null, we use it for the result, and jump to `done`.
6177      __ CompareAndBranchIfZero(out, &done);
6178      __ cmp(out, ShifterOperand(cls));
6179      __ b(&loop, NE);
6180      __ LoadImmediate(out, 1);
6181      if (zero.IsLinked()) {
6182        __ b(&done);
6183      }
6184      break;
6185    }
6186
6187    case TypeCheckKind::kClassHierarchyCheck: {
6188      // /* HeapReference<Class> */ out = obj->klass_
6189      GenerateReferenceLoadTwoRegisters(instruction,
6190                                        out_loc,
6191                                        obj_loc,
6192                                        class_offset,
6193                                        maybe_temp_loc,
6194                                        kCompilerReadBarrierOption);
6195      // Walk over the class hierarchy to find a match.
6196      Label loop, success;
6197      __ Bind(&loop);
6198      __ cmp(out, ShifterOperand(cls));
6199      __ b(&success, EQ);
6200      // /* HeapReference<Class> */ out = out->super_class_
6201      GenerateReferenceLoadOneRegister(instruction,
6202                                       out_loc,
6203                                       super_offset,
6204                                       maybe_temp_loc,
6205                                       kCompilerReadBarrierOption);
6206      __ CompareAndBranchIfNonZero(out, &loop);
6207      // If `out` is null, we use it for the result, and jump to `done`.
6208      __ b(&done);
6209      __ Bind(&success);
6210      __ LoadImmediate(out, 1);
6211      if (zero.IsLinked()) {
6212        __ b(&done);
6213      }
6214      break;
6215    }
6216
6217    case TypeCheckKind::kArrayObjectCheck: {
6218      // /* HeapReference<Class> */ out = obj->klass_
6219      GenerateReferenceLoadTwoRegisters(instruction,
6220                                        out_loc,
6221                                        obj_loc,
6222                                        class_offset,
6223                                        maybe_temp_loc,
6224                                        kCompilerReadBarrierOption);
6225      // Do an exact check.
6226      Label exact_check;
6227      __ cmp(out, ShifterOperand(cls));
6228      __ b(&exact_check, EQ);
6229      // Otherwise, we need to check that the object's class is a non-primitive array.
6230      // /* HeapReference<Class> */ out = out->component_type_
6231      GenerateReferenceLoadOneRegister(instruction,
6232                                       out_loc,
6233                                       component_offset,
6234                                       maybe_temp_loc,
6235                                       kCompilerReadBarrierOption);
6236      // If `out` is null, we use it for the result, and jump to `done`.
6237      __ CompareAndBranchIfZero(out, &done);
6238      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
6239      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
6240      __ CompareAndBranchIfNonZero(out, &zero);
6241      __ Bind(&exact_check);
6242      __ LoadImmediate(out, 1);
6243      __ b(&done);
6244      break;
6245    }
6246
6247    case TypeCheckKind::kArrayCheck: {
6248      // No read barrier since the slow path will retry upon failure.
6249      // /* HeapReference<Class> */ out = obj->klass_
6250      GenerateReferenceLoadTwoRegisters(instruction,
6251                                        out_loc,
6252                                        obj_loc,
6253                                        class_offset,
6254                                        maybe_temp_loc,
6255                                        kWithoutReadBarrier);
6256      __ cmp(out, ShifterOperand(cls));
6257      DCHECK(locations->OnlyCallsOnSlowPath());
6258      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6259                                                                    /* is_fatal */ false);
6260      codegen_->AddSlowPath(slow_path);
6261      __ b(slow_path->GetEntryLabel(), NE);
6262      __ LoadImmediate(out, 1);
6263      if (zero.IsLinked()) {
6264        __ b(&done);
6265      }
6266      break;
6267    }
6268
6269    case TypeCheckKind::kUnresolvedCheck:
6270    case TypeCheckKind::kInterfaceCheck: {
6271      // Note that we indeed only call on slow path, but we always go
6272      // into the slow path for the unresolved and interface check
6273      // cases.
6274      //
6275      // We cannot directly call the InstanceofNonTrivial runtime
6276      // entry point without resorting to a type checking slow path
6277      // here (i.e. by calling InvokeRuntime directly), as it would
6278      // require to assign fixed registers for the inputs of this
6279      // HInstanceOf instruction (following the runtime calling
6280      // convention), which might be cluttered by the potential first
6281      // read barrier emission at the beginning of this method.
6282      //
6283      // TODO: Introduce a new runtime entry point taking the object
6284      // to test (instead of its class) as argument, and let it deal
6285      // with the read barrier issues. This will let us refactor this
6286      // case of the `switch` code as it was previously (with a direct
6287      // call to the runtime not using a type checking slow path).
6288      // This should also be beneficial for the other cases above.
6289      DCHECK(locations->OnlyCallsOnSlowPath());
6290      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6291                                                                    /* is_fatal */ false);
6292      codegen_->AddSlowPath(slow_path);
6293      __ b(slow_path->GetEntryLabel());
6294      if (zero.IsLinked()) {
6295        __ b(&done);
6296      }
6297      break;
6298    }
6299  }
6300
6301  if (zero.IsLinked()) {
6302    __ Bind(&zero);
6303    __ LoadImmediate(out, 0);
6304  }
6305
6306  if (done.IsLinked()) {
6307    __ Bind(&done);
6308  }
6309
6310  if (slow_path != nullptr) {
6311    __ Bind(slow_path->GetExitLabel());
6312  }
6313}
6314
6315void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
6316  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
6317  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
6318
6319  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6320  switch (type_check_kind) {
6321    case TypeCheckKind::kExactCheck:
6322    case TypeCheckKind::kAbstractClassCheck:
6323    case TypeCheckKind::kClassHierarchyCheck:
6324    case TypeCheckKind::kArrayObjectCheck:
6325      call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
6326          LocationSummary::kCallOnSlowPath :
6327          LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
6328      break;
6329    case TypeCheckKind::kArrayCheck:
6330    case TypeCheckKind::kUnresolvedCheck:
6331    case TypeCheckKind::kInterfaceCheck:
6332      call_kind = LocationSummary::kCallOnSlowPath;
6333      break;
6334  }
6335
6336  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
6337  locations->SetInAt(0, Location::RequiresRegister());
6338  locations->SetInAt(1, Location::RequiresRegister());
6339  locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
6340}
6341
6342void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
6343  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
6344  LocationSummary* locations = instruction->GetLocations();
6345  Location obj_loc = locations->InAt(0);
6346  Register obj = obj_loc.AsRegister<Register>();
6347  Register cls = locations->InAt(1).AsRegister<Register>();
6348  Location temp_loc = locations->GetTemp(0);
6349  Register temp = temp_loc.AsRegister<Register>();
6350  const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
6351  DCHECK_LE(num_temps, 3u);
6352  Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
6353  Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
6354  const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6355  const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6356  const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6357  const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
6358  const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
6359  const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
6360  const uint32_t object_array_data_offset =
6361      mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
6362
6363  // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
6364  // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
6365  // read barriers is done for performance and code size reasons.
6366  bool is_type_check_slow_path_fatal = false;
6367  if (!kEmitCompilerReadBarrier) {
6368    is_type_check_slow_path_fatal =
6369        (type_check_kind == TypeCheckKind::kExactCheck ||
6370         type_check_kind == TypeCheckKind::kAbstractClassCheck ||
6371         type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
6372         type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
6373        !instruction->CanThrowIntoCatchBlock();
6374  }
6375  SlowPathCodeARM* type_check_slow_path =
6376      new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
6377                                                        is_type_check_slow_path_fatal);
6378  codegen_->AddSlowPath(type_check_slow_path);
6379
6380  Label done;
6381  // Avoid null check if we know obj is not null.
6382  if (instruction->MustDoNullCheck()) {
6383    __ CompareAndBranchIfZero(obj, &done);
6384  }
6385
6386  switch (type_check_kind) {
6387    case TypeCheckKind::kExactCheck:
6388    case TypeCheckKind::kArrayCheck: {
6389      // /* HeapReference<Class> */ temp = obj->klass_
6390      GenerateReferenceLoadTwoRegisters(instruction,
6391                                        temp_loc,
6392                                        obj_loc,
6393                                        class_offset,
6394                                        maybe_temp2_loc,
6395                                        kWithoutReadBarrier);
6396
6397      __ cmp(temp, ShifterOperand(cls));
6398      // Jump to slow path for throwing the exception or doing a
6399      // more involved array check.
6400      __ b(type_check_slow_path->GetEntryLabel(), NE);
6401      break;
6402    }
6403
6404    case TypeCheckKind::kAbstractClassCheck: {
6405      // /* HeapReference<Class> */ temp = obj->klass_
6406      GenerateReferenceLoadTwoRegisters(instruction,
6407                                        temp_loc,
6408                                        obj_loc,
6409                                        class_offset,
6410                                        maybe_temp2_loc,
6411                                        kWithoutReadBarrier);
6412
6413      // If the class is abstract, we eagerly fetch the super class of the
6414      // object to avoid doing a comparison we know will fail.
6415      Label loop;
6416      __ Bind(&loop);
6417      // /* HeapReference<Class> */ temp = temp->super_class_
6418      GenerateReferenceLoadOneRegister(instruction,
6419                                       temp_loc,
6420                                       super_offset,
6421                                       maybe_temp2_loc,
6422                                       kWithoutReadBarrier);
6423
6424      // If the class reference currently in `temp` is null, jump to the slow path to throw the
6425      // exception.
6426      __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6427
6428      // Otherwise, compare the classes.
6429      __ cmp(temp, ShifterOperand(cls));
6430      __ b(&loop, NE);
6431      break;
6432    }
6433
6434    case TypeCheckKind::kClassHierarchyCheck: {
6435      // /* HeapReference<Class> */ temp = obj->klass_
6436      GenerateReferenceLoadTwoRegisters(instruction,
6437                                        temp_loc,
6438                                        obj_loc,
6439                                        class_offset,
6440                                        maybe_temp2_loc,
6441                                        kWithoutReadBarrier);
6442
6443      // Walk over the class hierarchy to find a match.
6444      Label loop;
6445      __ Bind(&loop);
6446      __ cmp(temp, ShifterOperand(cls));
6447      __ b(&done, EQ);
6448
6449      // /* HeapReference<Class> */ temp = temp->super_class_
6450      GenerateReferenceLoadOneRegister(instruction,
6451                                       temp_loc,
6452                                       super_offset,
6453                                       maybe_temp2_loc,
6454                                       kWithoutReadBarrier);
6455
6456      // If the class reference currently in `temp` is null, jump to the slow path to throw the
6457      // exception.
6458      __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6459      // Otherwise, jump to the beginning of the loop.
6460      __ b(&loop);
6461      break;
6462    }
6463
6464    case TypeCheckKind::kArrayObjectCheck: {
6465      // /* HeapReference<Class> */ temp = obj->klass_
6466      GenerateReferenceLoadTwoRegisters(instruction,
6467                                        temp_loc,
6468                                        obj_loc,
6469                                        class_offset,
6470                                        maybe_temp2_loc,
6471                                        kWithoutReadBarrier);
6472
6473      // Do an exact check.
6474      __ cmp(temp, ShifterOperand(cls));
6475      __ b(&done, EQ);
6476
6477      // Otherwise, we need to check that the object's class is a non-primitive array.
6478      // /* HeapReference<Class> */ temp = temp->component_type_
6479      GenerateReferenceLoadOneRegister(instruction,
6480                                       temp_loc,
6481                                       component_offset,
6482                                       maybe_temp2_loc,
6483                                       kWithoutReadBarrier);
6484      // If the component type is null, jump to the slow path to throw the exception.
6485      __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
6486      // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
6487      // to further check that this component type is not a primitive type.
6488      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
6489      static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
6490      __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
6491      break;
6492    }
6493
6494    case TypeCheckKind::kUnresolvedCheck:
6495      // We always go into the type check slow path for the unresolved check case.
6496      // We cannot directly call the CheckCast runtime entry point
6497      // without resorting to a type checking slow path here (i.e. by
6498      // calling InvokeRuntime directly), as it would require to
6499      // assign fixed registers for the inputs of this HInstanceOf
6500      // instruction (following the runtime calling convention), which
6501      // might be cluttered by the potential first read barrier
6502      // emission at the beginning of this method.
6503
6504      __ b(type_check_slow_path->GetEntryLabel());
6505      break;
6506
6507    case TypeCheckKind::kInterfaceCheck: {
6508      // Avoid read barriers to improve performance of the fast path. We can not get false
6509      // positives by doing this.
6510      // /* HeapReference<Class> */ temp = obj->klass_
6511      GenerateReferenceLoadTwoRegisters(instruction,
6512                                        temp_loc,
6513                                        obj_loc,
6514                                        class_offset,
6515                                        maybe_temp2_loc,
6516                                        kWithoutReadBarrier);
6517
6518      // /* HeapReference<Class> */ temp = temp->iftable_
6519      GenerateReferenceLoadTwoRegisters(instruction,
6520                                        temp_loc,
6521                                        temp_loc,
6522                                        iftable_offset,
6523                                        maybe_temp2_loc,
6524                                        kWithoutReadBarrier);
6525      // Iftable is never null.
6526      __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
6527      // Loop through the iftable and check if any class matches.
6528      Label start_loop;
6529      __ Bind(&start_loop);
6530      __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
6531                                type_check_slow_path->GetEntryLabel());
6532      __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
6533      __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
6534      // Go to next interface.
6535      __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
6536      __ sub(maybe_temp2_loc.AsRegister<Register>(),
6537             maybe_temp2_loc.AsRegister<Register>(),
6538             ShifterOperand(2));
6539      // Compare the classes and continue the loop if they do not match.
6540      __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
6541      __ b(&start_loop, NE);
6542      break;
6543    }
6544  }
6545  __ Bind(&done);
6546
6547  __ Bind(type_check_slow_path->GetExitLabel());
6548}
6549
6550void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6551  LocationSummary* locations =
6552      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
6553  InvokeRuntimeCallingConvention calling_convention;
6554  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6555}
6556
6557void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6558  codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
6559                          instruction,
6560                          instruction->GetDexPc());
6561  if (instruction->IsEnter()) {
6562    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6563  } else {
6564    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6565  }
6566}
6567
6568void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
6569void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
6570void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
6571
6572void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
6573  LocationSummary* locations =
6574      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6575  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6576         || instruction->GetResultType() == Primitive::kPrimLong);
6577  // Note: GVN reorders commutative operations to have the constant on the right hand side.
6578  locations->SetInAt(0, Location::RequiresRegister());
6579  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
6580  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6581}
6582
6583void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
6584  HandleBitwiseOperation(instruction);
6585}
6586
6587void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
6588  HandleBitwiseOperation(instruction);
6589}
6590
6591void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
6592  HandleBitwiseOperation(instruction);
6593}
6594
6595
6596void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6597  LocationSummary* locations =
6598      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6599  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6600         || instruction->GetResultType() == Primitive::kPrimLong);
6601
6602  locations->SetInAt(0, Location::RequiresRegister());
6603  locations->SetInAt(1, Location::RequiresRegister());
6604  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6605}
6606
6607void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6608  LocationSummary* locations = instruction->GetLocations();
6609  Location first = locations->InAt(0);
6610  Location second = locations->InAt(1);
6611  Location out = locations->Out();
6612
6613  if (instruction->GetResultType() == Primitive::kPrimInt) {
6614    Register first_reg = first.AsRegister<Register>();
6615    ShifterOperand second_reg(second.AsRegister<Register>());
6616    Register out_reg = out.AsRegister<Register>();
6617
6618    switch (instruction->GetOpKind()) {
6619      case HInstruction::kAnd:
6620        __ bic(out_reg, first_reg, second_reg);
6621        break;
6622      case HInstruction::kOr:
6623        __ orn(out_reg, first_reg, second_reg);
6624        break;
6625      // There is no EON on arm.
6626      case HInstruction::kXor:
6627      default:
6628        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6629        UNREACHABLE();
6630    }
6631    return;
6632
6633  } else {
6634    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6635    Register first_low = first.AsRegisterPairLow<Register>();
6636    Register first_high = first.AsRegisterPairHigh<Register>();
6637    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6638    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6639    Register out_low = out.AsRegisterPairLow<Register>();
6640    Register out_high = out.AsRegisterPairHigh<Register>();
6641
6642    switch (instruction->GetOpKind()) {
6643      case HInstruction::kAnd:
6644        __ bic(out_low, first_low, second_low);
6645        __ bic(out_high, first_high, second_high);
6646        break;
6647      case HInstruction::kOr:
6648        __ orn(out_low, first_low, second_low);
6649        __ orn(out_high, first_high, second_high);
6650        break;
6651      // There is no EON on arm.
6652      case HInstruction::kXor:
6653      default:
6654        LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6655        UNREACHABLE();
6656    }
6657  }
6658}
6659
6660void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
6661  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
6662  if (value == 0xffffffffu) {
6663    if (out != first) {
6664      __ mov(out, ShifterOperand(first));
6665    }
6666    return;
6667  }
6668  if (value == 0u) {
6669    __ mov(out, ShifterOperand(0));
6670    return;
6671  }
6672  ShifterOperand so;
6673  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
6674    __ and_(out, first, so);
6675  } else {
6676    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
6677    __ bic(out, first, ShifterOperand(~value));
6678  }
6679}
6680
6681void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
6682  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
6683  if (value == 0u) {
6684    if (out != first) {
6685      __ mov(out, ShifterOperand(first));
6686    }
6687    return;
6688  }
6689  if (value == 0xffffffffu) {
6690    __ mvn(out, ShifterOperand(0));
6691    return;
6692  }
6693  ShifterOperand so;
6694  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
6695    __ orr(out, first, so);
6696  } else {
6697    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
6698    __ orn(out, first, ShifterOperand(~value));
6699  }
6700}
6701
6702void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6703  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6704  if (value == 0u) {
6705    if (out != first) {
6706      __ mov(out, ShifterOperand(first));
6707    }
6708    return;
6709  }
6710  __ eor(out, first, ShifterOperand(value));
6711}
6712
6713void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
6714                                                       Location first,
6715                                                       uint64_t value) {
6716  Register out_low = out.AsRegisterPairLow<Register>();
6717  Register out_high = out.AsRegisterPairHigh<Register>();
6718  Register first_low = first.AsRegisterPairLow<Register>();
6719  Register first_high = first.AsRegisterPairHigh<Register>();
6720  uint32_t value_low = Low32Bits(value);
6721  uint32_t value_high = High32Bits(value);
6722  if (value_low == 0u) {
6723    if (out_low != first_low) {
6724      __ mov(out_low, ShifterOperand(first_low));
6725    }
6726    __ AddConstant(out_high, first_high, value_high);
6727    return;
6728  }
6729  __ AddConstantSetFlags(out_low, first_low, value_low);
6730  ShifterOperand so;
6731  if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
6732    __ adc(out_high, first_high, so);
6733  } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
6734    __ sbc(out_high, first_high, so);
6735  } else {
6736    LOG(FATAL) << "Unexpected constant " << value_high;
6737    UNREACHABLE();
6738  }
6739}
6740
6741void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6742  LocationSummary* locations = instruction->GetLocations();
6743  Location first = locations->InAt(0);
6744  Location second = locations->InAt(1);
6745  Location out = locations->Out();
6746
6747  if (second.IsConstant()) {
6748    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6749    uint32_t value_low = Low32Bits(value);
6750    if (instruction->GetResultType() == Primitive::kPrimInt) {
6751      Register first_reg = first.AsRegister<Register>();
6752      Register out_reg = out.AsRegister<Register>();
6753      if (instruction->IsAnd()) {
6754        GenerateAndConst(out_reg, first_reg, value_low);
6755      } else if (instruction->IsOr()) {
6756        GenerateOrrConst(out_reg, first_reg, value_low);
6757      } else {
6758        DCHECK(instruction->IsXor());
6759        GenerateEorConst(out_reg, first_reg, value_low);
6760      }
6761    } else {
6762      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6763      uint32_t value_high = High32Bits(value);
6764      Register first_low = first.AsRegisterPairLow<Register>();
6765      Register first_high = first.AsRegisterPairHigh<Register>();
6766      Register out_low = out.AsRegisterPairLow<Register>();
6767      Register out_high = out.AsRegisterPairHigh<Register>();
6768      if (instruction->IsAnd()) {
6769        GenerateAndConst(out_low, first_low, value_low);
6770        GenerateAndConst(out_high, first_high, value_high);
6771      } else if (instruction->IsOr()) {
6772        GenerateOrrConst(out_low, first_low, value_low);
6773        GenerateOrrConst(out_high, first_high, value_high);
6774      } else {
6775        DCHECK(instruction->IsXor());
6776        GenerateEorConst(out_low, first_low, value_low);
6777        GenerateEorConst(out_high, first_high, value_high);
6778      }
6779    }
6780    return;
6781  }
6782
6783  if (instruction->GetResultType() == Primitive::kPrimInt) {
6784    Register first_reg = first.AsRegister<Register>();
6785    ShifterOperand second_reg(second.AsRegister<Register>());
6786    Register out_reg = out.AsRegister<Register>();
6787    if (instruction->IsAnd()) {
6788      __ and_(out_reg, first_reg, second_reg);
6789    } else if (instruction->IsOr()) {
6790      __ orr(out_reg, first_reg, second_reg);
6791    } else {
6792      DCHECK(instruction->IsXor());
6793      __ eor(out_reg, first_reg, second_reg);
6794    }
6795  } else {
6796    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6797    Register first_low = first.AsRegisterPairLow<Register>();
6798    Register first_high = first.AsRegisterPairHigh<Register>();
6799    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6800    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6801    Register out_low = out.AsRegisterPairLow<Register>();
6802    Register out_high = out.AsRegisterPairHigh<Register>();
6803    if (instruction->IsAnd()) {
6804      __ and_(out_low, first_low, second_low);
6805      __ and_(out_high, first_high, second_high);
6806    } else if (instruction->IsOr()) {
6807      __ orr(out_low, first_low, second_low);
6808      __ orr(out_high, first_high, second_high);
6809    } else {
6810      DCHECK(instruction->IsXor());
6811      __ eor(out_low, first_low, second_low);
6812      __ eor(out_high, first_high, second_high);
6813    }
6814  }
6815}
6816
6817void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
6818    HInstruction* instruction,
6819    Location out,
6820    uint32_t offset,
6821    Location maybe_temp,
6822    ReadBarrierOption read_barrier_option) {
6823  Register out_reg = out.AsRegister<Register>();
6824  if (read_barrier_option == kWithReadBarrier) {
6825    CHECK(kEmitCompilerReadBarrier);
6826    DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6827    if (kUseBakerReadBarrier) {
6828      // Load with fast path based Baker's read barrier.
6829      // /* HeapReference<Object> */ out = *(out + offset)
6830      codegen_->GenerateFieldLoadWithBakerReadBarrier(
6831          instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
6832    } else {
6833      // Load with slow path based read barrier.
6834      // Save the value of `out` into `maybe_temp` before overwriting it
6835      // in the following move operation, as we will need it for the
6836      // read barrier below.
6837      __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
6838      // /* HeapReference<Object> */ out = *(out + offset)
6839      __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6840      codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6841    }
6842  } else {
6843    // Plain load with no read barrier.
6844    // /* HeapReference<Object> */ out = *(out + offset)
6845    __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6846    __ MaybeUnpoisonHeapReference(out_reg);
6847  }
6848}
6849
6850void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
6851    HInstruction* instruction,
6852    Location out,
6853    Location obj,
6854    uint32_t offset,
6855    Location maybe_temp,
6856    ReadBarrierOption read_barrier_option) {
6857  Register out_reg = out.AsRegister<Register>();
6858  Register obj_reg = obj.AsRegister<Register>();
6859  if (read_barrier_option == kWithReadBarrier) {
6860    CHECK(kEmitCompilerReadBarrier);
6861    if (kUseBakerReadBarrier) {
6862      DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6863      // Load with fast path based Baker's read barrier.
6864      // /* HeapReference<Object> */ out = *(obj + offset)
6865      codegen_->GenerateFieldLoadWithBakerReadBarrier(
6866          instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
6867    } else {
6868      // Load with slow path based read barrier.
6869      // /* HeapReference<Object> */ out = *(obj + offset)
6870      __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6871      codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6872    }
6873  } else {
6874    // Plain load with no read barrier.
6875    // /* HeapReference<Object> */ out = *(obj + offset)
6876    __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6877    __ MaybeUnpoisonHeapReference(out_reg);
6878  }
6879}
6880
6881void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6882                                                          Location root,
6883                                                          Register obj,
6884                                                          uint32_t offset,
6885                                                          ReadBarrierOption read_barrier_option) {
6886  Register root_reg = root.AsRegister<Register>();
6887  if (read_barrier_option == kWithReadBarrier) {
6888    DCHECK(kEmitCompilerReadBarrier);
6889    if (kUseBakerReadBarrier) {
6890      // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6891      // Baker's read barrier are used:
6892      //
6893      //   root = obj.field;
6894      //   temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6895      //   if (temp != null) {
6896      //     root = temp(root)
6897      //   }
6898
6899      // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6900      __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6901      static_assert(
6902          sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6903          "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6904          "have different sizes.");
6905      static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6906                    "art::mirror::CompressedReference<mirror::Object> and int32_t "
6907                    "have different sizes.");
6908
6909      // Slow path marking the GC root `root`.
6910      Location temp = Location::RegisterLocation(LR);
6911      SlowPathCodeARM* slow_path =
6912          new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
6913              instruction,
6914              root,
6915              /*entrypoint*/ temp);
6916      codegen_->AddSlowPath(slow_path);
6917
6918      // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6919      const int32_t entry_point_offset =
6920          CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
6921      // Loading the entrypoint does not require a load acquire since it is only changed when
6922      // threads are suspended or running a checkpoint.
6923      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
6924      // The entrypoint is null when the GC is not marking, this prevents one load compared to
6925      // checking GetIsGcMarking.
6926      __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
6927      __ Bind(slow_path->GetExitLabel());
6928    } else {
6929      // GC root loaded through a slow path for read barriers other
6930      // than Baker's.
6931      // /* GcRoot<mirror::Object>* */ root = obj + offset
6932      __ AddConstant(root_reg, obj, offset);
6933      // /* mirror::Object* */ root = root->Read()
6934      codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6935    }
6936  } else {
6937    // Plain GC root load with no read barrier.
6938    // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6939    __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6940    // Note that GC roots are not affected by heap poisoning, thus we
6941    // do not have to unpoison `root_reg` here.
6942  }
6943}
6944
6945void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6946                                                             Location ref,
6947                                                             Register obj,
6948                                                             uint32_t offset,
6949                                                             Location temp,
6950                                                             bool needs_null_check) {
6951  DCHECK(kEmitCompilerReadBarrier);
6952  DCHECK(kUseBakerReadBarrier);
6953
6954  // /* HeapReference<Object> */ ref = *(obj + offset)
6955  Location no_index = Location::NoLocation();
6956  ScaleFactor no_scale_factor = TIMES_1;
6957  GenerateReferenceLoadWithBakerReadBarrier(
6958      instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
6959}
6960
6961void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6962                                                             Location ref,
6963                                                             Register obj,
6964                                                             uint32_t data_offset,
6965                                                             Location index,
6966                                                             Location temp,
6967                                                             bool needs_null_check) {
6968  DCHECK(kEmitCompilerReadBarrier);
6969  DCHECK(kUseBakerReadBarrier);
6970
6971  static_assert(
6972      sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6973      "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6974  // /* HeapReference<Object> */ ref =
6975  //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
6976  ScaleFactor scale_factor = TIMES_4;
6977  GenerateReferenceLoadWithBakerReadBarrier(
6978      instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
6979}
6980
6981void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6982                                                                 Location ref,
6983                                                                 Register obj,
6984                                                                 uint32_t offset,
6985                                                                 Location index,
6986                                                                 ScaleFactor scale_factor,
6987                                                                 Location temp,
6988                                                                 bool needs_null_check,
6989                                                                 bool always_update_field,
6990                                                                 Register* temp2) {
6991  DCHECK(kEmitCompilerReadBarrier);
6992  DCHECK(kUseBakerReadBarrier);
6993
6994  // In slow path based read barriers, the read barrier call is
6995  // inserted after the original load. However, in fast path based
6996  // Baker's read barriers, we need to perform the load of
6997  // mirror::Object::monitor_ *before* the original reference load.
6998  // This load-load ordering is required by the read barrier.
6999  // The fast path/slow path (for Baker's algorithm) should look like:
7000  //
7001  //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
7002  //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
7003  //   HeapReference<Object> ref = *src;  // Original reference load.
7004  //   bool is_gray = (rb_state == ReadBarrier::GrayState());
7005  //   if (is_gray) {
7006  //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
7007  //   }
7008  //
7009  // Note: the original implementation in ReadBarrier::Barrier is
7010  // slightly more complex as it performs additional checks that we do
7011  // not do here for performance reasons.
7012
7013  Register ref_reg = ref.AsRegister<Register>();
7014  Register temp_reg = temp.AsRegister<Register>();
7015  uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7016
7017  // /* int32_t */ monitor = obj->monitor_
7018  __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
7019  if (needs_null_check) {
7020    MaybeRecordImplicitNullCheck(instruction);
7021  }
7022  // /* LockWord */ lock_word = LockWord(monitor)
7023  static_assert(sizeof(LockWord) == sizeof(int32_t),
7024                "art::LockWord and int32_t have different sizes.");
7025
7026  // Introduce a dependency on the lock_word including the rb_state,
7027  // which shall prevent load-load reordering without using
7028  // a memory barrier (which would be more expensive).
7029  // `obj` is unchanged by this operation, but its value now depends
7030  // on `temp_reg`.
7031  __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
7032
7033  // The actual reference load.
7034  if (index.IsValid()) {
7035    // Load types involving an "index": ArrayGet,
7036    // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7037    // intrinsics.
7038    // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
7039    if (index.IsConstant()) {
7040      size_t computed_offset =
7041          (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
7042      __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
7043    } else {
7044      // Handle the special case of the
7045      // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7046      // intrinsics, which use a register pair as index ("long
7047      // offset"), of which only the low part contains data.
7048      Register index_reg = index.IsRegisterPair()
7049          ? index.AsRegisterPairLow<Register>()
7050          : index.AsRegister<Register>();
7051      __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
7052      __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
7053    }
7054  } else {
7055    // /* HeapReference<Object> */ ref = *(obj + offset)
7056    __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
7057  }
7058
7059  // Object* ref = ref_addr->AsMirrorPtr()
7060  __ MaybeUnpoisonHeapReference(ref_reg);
7061
7062  // Slow path marking the object `ref` when it is gray.
7063  SlowPathCodeARM* slow_path;
7064  if (always_update_field) {
7065    DCHECK(temp2 != nullptr);
7066    // ReadBarrierMarkAndUpdateFieldSlowPathARM only supports address
7067    // of the form `obj + field_offset`, where `obj` is a register and
7068    // `field_offset` is a register pair (of which only the lower half
7069    // is used). Thus `offset` and `scale_factor` above are expected
7070    // to be null in this code path.
7071    DCHECK_EQ(offset, 0u);
7072    DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
7073    slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkAndUpdateFieldSlowPathARM(
7074        instruction, ref, obj, /* field_offset */ index, temp_reg, *temp2);
7075  } else {
7076    slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
7077  }
7078  AddSlowPath(slow_path);
7079
7080  // if (rb_state == ReadBarrier::GrayState())
7081  //   ref = ReadBarrier::Mark(ref);
7082  // Given the numeric representation, it's enough to check the low bit of the
7083  // rb_state. We do that by shifting the bit out of the lock word with LSRS
7084  // which can be a 16-bit instruction unlike the TST immediate.
7085  static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
7086  static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
7087  __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
7088  __ b(slow_path->GetEntryLabel(), CS);  // Carry flag is the last bit shifted out by LSRS.
7089  __ Bind(slow_path->GetExitLabel());
7090}
7091
7092void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
7093                                               Location out,
7094                                               Location ref,
7095                                               Location obj,
7096                                               uint32_t offset,
7097                                               Location index) {
7098  DCHECK(kEmitCompilerReadBarrier);
7099
7100  // Insert a slow path based read barrier *after* the reference load.
7101  //
7102  // If heap poisoning is enabled, the unpoisoning of the loaded
7103  // reference will be carried out by the runtime within the slow
7104  // path.
7105  //
7106  // Note that `ref` currently does not get unpoisoned (when heap
7107  // poisoning is enabled), which is alright as the `ref` argument is
7108  // not used by the artReadBarrierSlow entry point.
7109  //
7110  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
7111  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
7112      ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
7113  AddSlowPath(slow_path);
7114
7115  __ b(slow_path->GetEntryLabel());
7116  __ Bind(slow_path->GetExitLabel());
7117}
7118
7119void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7120                                                    Location out,
7121                                                    Location ref,
7122                                                    Location obj,
7123                                                    uint32_t offset,
7124                                                    Location index) {
7125  if (kEmitCompilerReadBarrier) {
7126    // Baker's read barriers shall be handled by the fast path
7127    // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
7128    DCHECK(!kUseBakerReadBarrier);
7129    // If heap poisoning is enabled, unpoisoning will be taken care of
7130    // by the runtime within the slow path.
7131    GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
7132  } else if (kPoisonHeapReferences) {
7133    __ UnpoisonHeapReference(out.AsRegister<Register>());
7134  }
7135}
7136
7137void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7138                                                      Location out,
7139                                                      Location root) {
7140  DCHECK(kEmitCompilerReadBarrier);
7141
7142  // Insert a slow path based read barrier *after* the GC root load.
7143  //
7144  // Note that GC roots are not affected by heap poisoning, so we do
7145  // not need to do anything special for this here.
7146  SlowPathCodeARM* slow_path =
7147      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
7148  AddSlowPath(slow_path);
7149
7150  __ b(slow_path->GetEntryLabel());
7151  __ Bind(slow_path->GetExitLabel());
7152}
7153
7154HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
7155      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
7156      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
7157  return desired_dispatch_info;
7158}
7159
7160Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
7161                                                                 Register temp) {
7162  DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
7163  Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7164  if (!invoke->GetLocations()->Intrinsified()) {
7165    return location.AsRegister<Register>();
7166  }
7167  // For intrinsics we allow any location, so it may be on the stack.
7168  if (!location.IsRegister()) {
7169    __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
7170    return temp;
7171  }
7172  // For register locations, check if the register was saved. If so, get it from the stack.
7173  // Note: There is a chance that the register was saved but not overwritten, so we could
7174  // save one load. However, since this is just an intrinsic slow path we prefer this
7175  // simple and more robust approach rather that trying to determine if that's the case.
7176  SlowPathCode* slow_path = GetCurrentSlowPath();
7177  if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
7178    int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
7179    __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
7180    return temp;
7181  }
7182  return location.AsRegister<Register>();
7183}
7184
7185Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
7186                                                                  Location temp) {
7187  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
7188  switch (invoke->GetMethodLoadKind()) {
7189    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
7190      uint32_t offset =
7191          GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
7192      // temp = thread->string_init_entrypoint
7193      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
7194      break;
7195    }
7196    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
7197      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7198      break;
7199    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
7200      __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
7201      break;
7202    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
7203      HArmDexCacheArraysBase* base =
7204          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
7205      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
7206                                                                temp.AsRegister<Register>());
7207      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
7208      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
7209      break;
7210    }
7211    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
7212      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7213      Register method_reg;
7214      Register reg = temp.AsRegister<Register>();
7215      if (current_method.IsRegister()) {
7216        method_reg = current_method.AsRegister<Register>();
7217      } else {
7218        DCHECK(invoke->GetLocations()->Intrinsified());
7219        DCHECK(!current_method.IsValid());
7220        method_reg = reg;
7221        __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
7222      }
7223      // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
7224      __ LoadFromOffset(kLoadWord,
7225                        reg,
7226                        method_reg,
7227                        ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
7228      // temp = temp[index_in_cache];
7229      // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
7230      uint32_t index_in_cache = invoke->GetDexMethodIndex();
7231      __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
7232      break;
7233    }
7234  }
7235  return callee_method;
7236}
7237
7238void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
7239  Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
7240
7241  switch (invoke->GetCodePtrLocation()) {
7242    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
7243      __ bl(GetFrameEntryLabel());
7244      break;
7245    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
7246      // LR = callee_method->entry_point_from_quick_compiled_code_
7247      __ LoadFromOffset(
7248          kLoadWord, LR, callee_method.AsRegister<Register>(),
7249          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
7250      // LR()
7251      __ blx(LR);
7252      break;
7253  }
7254
7255  DCHECK(!IsLeafMethod());
7256}
7257
7258void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
7259  Register temp = temp_location.AsRegister<Register>();
7260  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7261      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
7262
7263  // Use the calling convention instead of the location of the receiver, as
7264  // intrinsics may have put the receiver in a different register. In the intrinsics
7265  // slow path, the arguments have been moved to the right place, so here we are
7266  // guaranteed that the receiver is the first register of the calling convention.
7267  InvokeDexCallingConvention calling_convention;
7268  Register receiver = calling_convention.GetRegisterAt(0);
7269  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7270  // /* HeapReference<Class> */ temp = receiver->klass_
7271  __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
7272  MaybeRecordImplicitNullCheck(invoke);
7273  // Instead of simply (possibly) unpoisoning `temp` here, we should
7274  // emit a read barrier for the previous class reference load.
7275  // However this is not required in practice, as this is an
7276  // intermediate/temporary reference and because the current
7277  // concurrent copying collector keeps the from-space memory
7278  // intact/accessible until the end of the marking phase (the
7279  // concurrent copying collector may not in the future).
7280  __ MaybeUnpoisonHeapReference(temp);
7281  // temp = temp->GetMethodAt(method_offset);
7282  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
7283      kArmPointerSize).Int32Value();
7284  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7285  // LR = temp->GetEntryPoint();
7286  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
7287  // LR();
7288  __ blx(LR);
7289}
7290
7291CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
7292    const DexFile& dex_file, dex::StringIndex string_index) {
7293  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
7294}
7295
7296CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
7297    const DexFile& dex_file, dex::TypeIndex type_index) {
7298  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
7299}
7300
7301CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
7302    const DexFile& dex_file, dex::TypeIndex type_index) {
7303  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
7304}
7305
7306CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
7307    const DexFile& dex_file, uint32_t element_offset) {
7308  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
7309}
7310
7311CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
7312    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
7313  patches->emplace_back(dex_file, offset_or_index);
7314  return &patches->back();
7315}
7316
7317Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
7318                                                             dex::StringIndex string_index) {
7319  return boot_image_string_patches_.GetOrCreate(
7320      StringReference(&dex_file, string_index),
7321      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7322}
7323
7324Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
7325                                                           dex::TypeIndex type_index) {
7326  return boot_image_type_patches_.GetOrCreate(
7327      TypeReference(&dex_file, type_index),
7328      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7329}
7330
7331Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
7332  bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
7333  Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
7334  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
7335}
7336
7337Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
7338                                                       dex::StringIndex string_index,
7339                                                       Handle<mirror::String> handle) {
7340  jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
7341                              reinterpret_cast64<uint64_t>(handle.GetReference()));
7342  return jit_string_patches_.GetOrCreate(
7343      StringReference(&dex_file, string_index),
7344      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7345}
7346
7347Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
7348                                                      dex::TypeIndex type_index,
7349                                                      Handle<mirror::Class> handle) {
7350  jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
7351                             reinterpret_cast64<uint64_t>(handle.GetReference()));
7352  return jit_class_patches_.GetOrCreate(
7353      TypeReference(&dex_file, type_index),
7354      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7355}
7356
7357template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
7358inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
7359    const ArenaDeque<PcRelativePatchInfo>& infos,
7360    ArenaVector<LinkerPatch>* linker_patches) {
7361  for (const PcRelativePatchInfo& info : infos) {
7362    const DexFile& dex_file = info.target_dex_file;
7363    size_t offset_or_index = info.offset_or_index;
7364    DCHECK(info.add_pc_label.IsBound());
7365    uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
7366    // Add MOVW patch.
7367    DCHECK(info.movw_label.IsBound());
7368    uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
7369    linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
7370    // Add MOVT patch.
7371    DCHECK(info.movt_label.IsBound());
7372    uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
7373    linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
7374  }
7375}
7376
7377void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
7378  DCHECK(linker_patches->empty());
7379  size_t size =
7380      /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
7381      boot_image_string_patches_.size() +
7382      /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
7383      boot_image_type_patches_.size() +
7384      /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
7385      /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
7386      boot_image_address_patches_.size();
7387  linker_patches->reserve(size);
7388  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
7389                                                               linker_patches);
7390  for (const auto& entry : boot_image_string_patches_) {
7391    const StringReference& target_string = entry.first;
7392    Literal* literal = entry.second;
7393    DCHECK(literal->GetLabel()->IsBound());
7394    uint32_t literal_offset = literal->GetLabel()->Position();
7395    linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
7396                                                       target_string.dex_file,
7397                                                       target_string.string_index.index_));
7398  }
7399  if (!GetCompilerOptions().IsBootImage()) {
7400    DCHECK(pc_relative_type_patches_.empty());
7401    EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
7402                                                                  linker_patches);
7403  } else {
7404    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
7405                                                                linker_patches);
7406    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
7407                                                                  linker_patches);
7408  }
7409  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
7410                                                              linker_patches);
7411  for (const auto& entry : boot_image_type_patches_) {
7412    const TypeReference& target_type = entry.first;
7413    Literal* literal = entry.second;
7414    DCHECK(literal->GetLabel()->IsBound());
7415    uint32_t literal_offset = literal->GetLabel()->Position();
7416    linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
7417                                                     target_type.dex_file,
7418                                                     target_type.type_index.index_));
7419  }
7420  for (const auto& entry : boot_image_address_patches_) {
7421    DCHECK(GetCompilerOptions().GetIncludePatchInformation());
7422    Literal* literal = entry.second;
7423    DCHECK(literal->GetLabel()->IsBound());
7424    uint32_t literal_offset = literal->GetLabel()->Position();
7425    linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
7426  }
7427  DCHECK_EQ(size, linker_patches->size());
7428}
7429
7430Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
7431  return map->GetOrCreate(
7432      value,
7433      [this, value]() { return __ NewLiteral<uint32_t>(value); });
7434}
7435
7436Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
7437                                                    MethodToLiteralMap* map) {
7438  return map->GetOrCreate(
7439      target_method,
7440      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
7441}
7442
7443void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7444  LocationSummary* locations =
7445      new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
7446  locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
7447                     Location::RequiresRegister());
7448  locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
7449  locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
7450  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7451}
7452
7453void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
7454  LocationSummary* locations = instr->GetLocations();
7455  Register res = locations->Out().AsRegister<Register>();
7456  Register accumulator =
7457      locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
7458  Register mul_left =
7459      locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
7460  Register mul_right =
7461      locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
7462
7463  if (instr->GetOpKind() == HInstruction::kAdd) {
7464    __ mla(res, mul_left, mul_right, accumulator);
7465  } else {
7466    __ mls(res, mul_left, mul_right, accumulator);
7467  }
7468}
7469
7470void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
7471  // Nothing to do, this should be removed during prepare for register allocator.
7472  LOG(FATAL) << "Unreachable";
7473}
7474
7475void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
7476  // Nothing to do, this should be removed during prepare for register allocator.
7477  LOG(FATAL) << "Unreachable";
7478}
7479
7480// Simple implementation of packed switch - generate cascaded compare/jumps.
7481void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7482  LocationSummary* locations =
7483      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
7484  locations->SetInAt(0, Location::RequiresRegister());
7485  if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
7486      codegen_->GetAssembler()->IsThumb()) {
7487    locations->AddTemp(Location::RequiresRegister());  // We need a temp for the table base.
7488    if (switch_instr->GetStartValue() != 0) {
7489      locations->AddTemp(Location::RequiresRegister());  // We need a temp for the bias.
7490    }
7491  }
7492}
7493
7494void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7495  int32_t lower_bound = switch_instr->GetStartValue();
7496  uint32_t num_entries = switch_instr->GetNumEntries();
7497  LocationSummary* locations = switch_instr->GetLocations();
7498  Register value_reg = locations->InAt(0).AsRegister<Register>();
7499  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7500
7501  if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
7502    // Create a series of compare/jumps.
7503    Register temp_reg = IP;
7504    // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
7505    // the immediate, because IP is used as the destination register. For the other
7506    // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
7507    // and they can be encoded in the instruction without making use of IP register.
7508    __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
7509
7510    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7511    // Jump to successors[0] if value == lower_bound.
7512    __ b(codegen_->GetLabelOf(successors[0]), EQ);
7513    int32_t last_index = 0;
7514    for (; num_entries - last_index > 2; last_index += 2) {
7515      __ AddConstantSetFlags(temp_reg, temp_reg, -2);
7516      // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
7517      __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
7518      // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
7519      __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
7520    }
7521    if (num_entries - last_index == 2) {
7522      // The last missing case_value.
7523      __ CmpConstant(temp_reg, 1);
7524      __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
7525    }
7526
7527    // And the default for any other value.
7528    if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7529      __ b(codegen_->GetLabelOf(default_block));
7530    }
7531  } else {
7532    // Create a table lookup.
7533    Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
7534
7535    // Materialize a pointer to the switch table
7536    std::vector<Label*> labels(num_entries);
7537    const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7538    for (uint32_t i = 0; i < num_entries; i++) {
7539      labels[i] = codegen_->GetLabelOf(successors[i]);
7540    }
7541    JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
7542
7543    // Remove the bias.
7544    Register key_reg;
7545    if (lower_bound != 0) {
7546      key_reg = locations->GetTemp(1).AsRegister<Register>();
7547      __ AddConstant(key_reg, value_reg, -lower_bound);
7548    } else {
7549      key_reg = value_reg;
7550    }
7551
7552    // Check whether the value is in the table, jump to default block if not.
7553    __ CmpConstant(key_reg, num_entries - 1);
7554    __ b(codegen_->GetLabelOf(default_block), Condition::HI);
7555
7556    // Load the displacement from the table.
7557    __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
7558
7559    // Dispatch is a direct add to the PC (for Thumb2).
7560    __ EmitJumpTableDispatch(table, temp_reg);
7561  }
7562}
7563
7564void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7565  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7566  locations->SetOut(Location::RequiresRegister());
7567}
7568
7569void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7570  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
7571  CodeGeneratorARM::PcRelativePatchInfo* labels =
7572      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
7573  __ BindTrackedLabel(&labels->movw_label);
7574  __ movw(base_reg, /* placeholder */ 0u);
7575  __ BindTrackedLabel(&labels->movt_label);
7576  __ movt(base_reg, /* placeholder */ 0u);
7577  __ BindTrackedLabel(&labels->add_pc_label);
7578  __ add(base_reg, base_reg, ShifterOperand(PC));
7579}
7580
7581void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7582  if (!trg.IsValid()) {
7583    DCHECK_EQ(type, Primitive::kPrimVoid);
7584    return;
7585  }
7586
7587  DCHECK_NE(type, Primitive::kPrimVoid);
7588
7589  Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
7590  if (return_loc.Equals(trg)) {
7591    return;
7592  }
7593
7594  // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
7595  //       with the last branch.
7596  if (type == Primitive::kPrimLong) {
7597    HParallelMove parallel_move(GetGraph()->GetArena());
7598    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
7599    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
7600    GetMoveResolver()->EmitNativeCode(&parallel_move);
7601  } else if (type == Primitive::kPrimDouble) {
7602    HParallelMove parallel_move(GetGraph()->GetArena());
7603    parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
7604    parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
7605    GetMoveResolver()->EmitNativeCode(&parallel_move);
7606  } else {
7607    // Let the parallel move resolver take care of all of this.
7608    HParallelMove parallel_move(GetGraph()->GetArena());
7609    parallel_move.AddMove(return_loc, trg, type, nullptr);
7610    GetMoveResolver()->EmitNativeCode(&parallel_move);
7611  }
7612}
7613
7614void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
7615  LocationSummary* locations =
7616      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7617  locations->SetInAt(0, Location::RequiresRegister());
7618  locations->SetOut(Location::RequiresRegister());
7619}
7620
7621void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
7622  LocationSummary* locations = instruction->GetLocations();
7623  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
7624    uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7625        instruction->GetIndex(), kArmPointerSize).SizeValue();
7626    __ LoadFromOffset(kLoadWord,
7627                      locations->Out().AsRegister<Register>(),
7628                      locations->InAt(0).AsRegister<Register>(),
7629                      method_offset);
7630  } else {
7631    uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
7632        instruction->GetIndex(), kArmPointerSize));
7633    __ LoadFromOffset(kLoadWord,
7634                      locations->Out().AsRegister<Register>(),
7635                      locations->InAt(0).AsRegister<Register>(),
7636                      mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
7637    __ LoadFromOffset(kLoadWord,
7638                      locations->Out().AsRegister<Register>(),
7639                      locations->Out().AsRegister<Register>(),
7640                      method_offset);
7641  }
7642}
7643
7644static void PatchJitRootUse(uint8_t* code,
7645                            const uint8_t* roots_data,
7646                            Literal* literal,
7647                            uint64_t index_in_table) {
7648  DCHECK(literal->GetLabel()->IsBound());
7649  uint32_t literal_offset = literal->GetLabel()->Position();
7650  uintptr_t address =
7651      reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
7652  uint8_t* data = code + literal_offset;
7653  reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
7654}
7655
7656void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
7657  for (const auto& entry : jit_string_patches_) {
7658    const auto& it = jit_string_roots_.find(entry.first);
7659    DCHECK(it != jit_string_roots_.end());
7660    PatchJitRootUse(code, roots_data, entry.second, it->second);
7661  }
7662  for (const auto& entry : jit_class_patches_) {
7663    const auto& it = jit_class_roots_.find(entry.first);
7664    DCHECK(it != jit_class_roots_.end());
7665    PatchJitRootUse(code, roots_data, entry.second, it->second);
7666  }
7667}
7668
7669#undef __
7670#undef QUICK_ENTRY_POINT
7671
7672}  // namespace arm
7673}  // namespace art
7674