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