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