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