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