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