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