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