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