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