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