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