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