code_generator_arm.cc revision acc0b8e3c7bad818edc9b777b89e97003b1eb4eb
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 "entrypoints/quick/quick_entrypoints.h"
21#include "gc/accounting/card_table.h"
22#include "intrinsics.h"
23#include "intrinsics_arm.h"
24#include "mirror/array-inl.h"
25#include "mirror/art_method.h"
26#include "mirror/class.h"
27#include "thread.h"
28#include "utils/arm/assembler_arm.h"
29#include "utils/arm/managed_register_arm.h"
30#include "utils/assembler.h"
31#include "utils/stack_checks.h"
32
33namespace art {
34
35namespace arm {
36
37static bool ExpectedPairLayout(Location location) {
38  // We expected this for both core and fpu register pairs.
39  return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
40}
41
42static constexpr int kCurrentMethodStackOffset = 0;
43
44// We unconditionally allocate R5 to ensure we can do long operations
45// with baseline.
46static constexpr Register kCoreSavedRegisterForBaseline = R5;
47static constexpr Register kCoreCalleeSaves[] =
48    { R5, R6, R7, R8, R10, R11, PC };
49static constexpr SRegister kFpuCalleeSaves[] =
50    { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
51
52// D31 cannot be split into two S registers, and the register allocator only works on
53// S registers. Therefore there is no need to block it.
54static constexpr DRegister DTMP = D31;
55
56#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
57#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
58
59class NullCheckSlowPathARM : public SlowPathCodeARM {
60 public:
61  explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
62
63  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
64    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
65    __ Bind(GetEntryLabel());
66    arm_codegen->InvokeRuntime(
67        QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
68  }
69
70 private:
71  HNullCheck* const instruction_;
72  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
73};
74
75class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
76 public:
77  explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
78
79  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
80    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
81    __ Bind(GetEntryLabel());
82    arm_codegen->InvokeRuntime(
83        QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
84  }
85
86 private:
87  HDivZeroCheck* const instruction_;
88  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
89};
90
91class SuspendCheckSlowPathARM : public SlowPathCodeARM {
92 public:
93  SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
94      : instruction_(instruction), successor_(successor) {}
95
96  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
97    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
98    __ Bind(GetEntryLabel());
99    SaveLiveRegisters(codegen, instruction_->GetLocations());
100    arm_codegen->InvokeRuntime(
101        QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
102    RestoreLiveRegisters(codegen, instruction_->GetLocations());
103    if (successor_ == nullptr) {
104      __ b(GetReturnLabel());
105    } else {
106      __ b(arm_codegen->GetLabelOf(successor_));
107    }
108  }
109
110  Label* GetReturnLabel() {
111    DCHECK(successor_ == nullptr);
112    return &return_label_;
113  }
114
115 private:
116  HSuspendCheck* const instruction_;
117  // If not null, the block to branch to after the suspend check.
118  HBasicBlock* const successor_;
119
120  // If `successor_` is null, the label to branch to after the suspend check.
121  Label return_label_;
122
123  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
124};
125
126class BoundsCheckSlowPathARM : public SlowPathCodeARM {
127 public:
128  BoundsCheckSlowPathARM(HBoundsCheck* instruction,
129                         Location index_location,
130                         Location length_location)
131      : instruction_(instruction),
132        index_location_(index_location),
133        length_location_(length_location) {}
134
135  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
136    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
137    __ Bind(GetEntryLabel());
138    // We're moving two locations to locations that could overlap, so we need a parallel
139    // move resolver.
140    InvokeRuntimeCallingConvention calling_convention;
141    codegen->EmitParallelMoves(
142        index_location_,
143        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
144        Primitive::kPrimInt,
145        length_location_,
146        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
147        Primitive::kPrimInt);
148    arm_codegen->InvokeRuntime(
149        QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
150  }
151
152 private:
153  HBoundsCheck* const instruction_;
154  const Location index_location_;
155  const Location length_location_;
156
157  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
158};
159
160class LoadClassSlowPathARM : public SlowPathCodeARM {
161 public:
162  LoadClassSlowPathARM(HLoadClass* cls,
163                       HInstruction* at,
164                       uint32_t dex_pc,
165                       bool do_clinit)
166      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
167    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
168  }
169
170  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
171    LocationSummary* locations = at_->GetLocations();
172
173    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
174    __ Bind(GetEntryLabel());
175    SaveLiveRegisters(codegen, locations);
176
177    InvokeRuntimeCallingConvention calling_convention;
178    __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
179    arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
180    int32_t entry_point_offset = do_clinit_
181        ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
182        : QUICK_ENTRY_POINT(pInitializeType);
183    arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
184
185    // Move the class to the desired location.
186    Location out = locations->Out();
187    if (out.IsValid()) {
188      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
189      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
190    }
191    RestoreLiveRegisters(codegen, locations);
192    __ b(GetExitLabel());
193  }
194
195 private:
196  // The class this slow path will load.
197  HLoadClass* const cls_;
198
199  // The instruction where this slow path is happening.
200  // (Might be the load class or an initialization check).
201  HInstruction* const at_;
202
203  // The dex PC of `at_`.
204  const uint32_t dex_pc_;
205
206  // Whether to initialize the class.
207  const bool do_clinit_;
208
209  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
210};
211
212class LoadStringSlowPathARM : public SlowPathCodeARM {
213 public:
214  explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
215
216  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
217    LocationSummary* locations = instruction_->GetLocations();
218    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
219
220    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
221    __ Bind(GetEntryLabel());
222    SaveLiveRegisters(codegen, locations);
223
224    InvokeRuntimeCallingConvention calling_convention;
225    arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
226    __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
227    arm_codegen->InvokeRuntime(
228        QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
229    arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
230
231    RestoreLiveRegisters(codegen, locations);
232    __ b(GetExitLabel());
233  }
234
235 private:
236  HLoadString* const instruction_;
237
238  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
239};
240
241class TypeCheckSlowPathARM : public SlowPathCodeARM {
242 public:
243  TypeCheckSlowPathARM(HInstruction* instruction,
244                       Location class_to_check,
245                       Location object_class,
246                       uint32_t dex_pc)
247      : instruction_(instruction),
248        class_to_check_(class_to_check),
249        object_class_(object_class),
250        dex_pc_(dex_pc) {}
251
252  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
253    LocationSummary* locations = instruction_->GetLocations();
254    DCHECK(instruction_->IsCheckCast()
255           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
256
257    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
258    __ Bind(GetEntryLabel());
259    SaveLiveRegisters(codegen, locations);
260
261    // We're moving two locations to locations that could overlap, so we need a parallel
262    // move resolver.
263    InvokeRuntimeCallingConvention calling_convention;
264    codegen->EmitParallelMoves(
265        class_to_check_,
266        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
267        Primitive::kPrimNot,
268        object_class_,
269        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
270        Primitive::kPrimNot);
271
272    if (instruction_->IsInstanceOf()) {
273      arm_codegen->InvokeRuntime(
274          QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
275      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
276    } else {
277      DCHECK(instruction_->IsCheckCast());
278      arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
279    }
280
281    RestoreLiveRegisters(codegen, locations);
282    __ b(GetExitLabel());
283  }
284
285 private:
286  HInstruction* const instruction_;
287  const Location class_to_check_;
288  const Location object_class_;
289  uint32_t dex_pc_;
290
291  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
292};
293
294class DeoptimizationSlowPathARM : public SlowPathCodeARM {
295 public:
296  explicit DeoptimizationSlowPathARM(HInstruction* instruction)
297    : instruction_(instruction) {}
298
299  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
300    __ Bind(GetEntryLabel());
301    SaveLiveRegisters(codegen, instruction_->GetLocations());
302    DCHECK(instruction_->IsDeoptimize());
303    HDeoptimize* deoptimize = instruction_->AsDeoptimize();
304    uint32_t dex_pc = deoptimize->GetDexPc();
305    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
306    arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
307  }
308
309 private:
310  HInstruction* const instruction_;
311  DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
312};
313
314#undef __
315
316#undef __
317#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
318
319inline Condition ARMCondition(IfCondition cond) {
320  switch (cond) {
321    case kCondEQ: return EQ;
322    case kCondNE: return NE;
323    case kCondLT: return LT;
324    case kCondLE: return LE;
325    case kCondGT: return GT;
326    case kCondGE: return GE;
327    default:
328      LOG(FATAL) << "Unknown if condition";
329  }
330  return EQ;        // Unreachable.
331}
332
333inline Condition ARMOppositeCondition(IfCondition cond) {
334  switch (cond) {
335    case kCondEQ: return NE;
336    case kCondNE: return EQ;
337    case kCondLT: return GE;
338    case kCondLE: return GT;
339    case kCondGT: return LE;
340    case kCondGE: return LT;
341    default:
342      LOG(FATAL) << "Unknown if condition";
343  }
344  return EQ;        // Unreachable.
345}
346
347void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
348  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
349}
350
351void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
352  stream << ArmManagedRegister::FromSRegister(SRegister(reg));
353}
354
355size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
356  __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
357  return kArmWordSize;
358}
359
360size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
361  __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
362  return kArmWordSize;
363}
364
365size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
366  __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
367  return kArmWordSize;
368}
369
370size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
371  __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
372  return kArmWordSize;
373}
374
375CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
376                                   const ArmInstructionSetFeatures& isa_features,
377                                   const CompilerOptions& compiler_options)
378    : CodeGenerator(graph,
379                    kNumberOfCoreRegisters,
380                    kNumberOfSRegisters,
381                    kNumberOfRegisterPairs,
382                    ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
383                                        arraysize(kCoreCalleeSaves)),
384                    ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
385                                        arraysize(kFpuCalleeSaves)),
386                    compiler_options),
387      block_labels_(graph->GetArena(), 0),
388      location_builder_(graph, this),
389      instruction_visitor_(graph, this),
390      move_resolver_(graph->GetArena(), this),
391      assembler_(true),
392      isa_features_(isa_features) {
393  // Save the PC register to mimic Quick.
394  AddAllocatedRegister(Location::RegisterLocation(PC));
395}
396
397Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
398  switch (type) {
399    case Primitive::kPrimLong: {
400      size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
401      ArmManagedRegister pair =
402          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
403      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
404      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
405
406      blocked_core_registers_[pair.AsRegisterPairLow()] = true;
407      blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
408      UpdateBlockedPairRegisters();
409      return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
410    }
411
412    case Primitive::kPrimByte:
413    case Primitive::kPrimBoolean:
414    case Primitive::kPrimChar:
415    case Primitive::kPrimShort:
416    case Primitive::kPrimInt:
417    case Primitive::kPrimNot: {
418      int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
419      // Block all register pairs that contain `reg`.
420      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
421        ArmManagedRegister current =
422            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
423        if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
424          blocked_register_pairs_[i] = true;
425        }
426      }
427      return Location::RegisterLocation(reg);
428    }
429
430    case Primitive::kPrimFloat: {
431      int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
432      return Location::FpuRegisterLocation(reg);
433    }
434
435    case Primitive::kPrimDouble: {
436      int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
437      DCHECK_EQ(reg % 2, 0);
438      return Location::FpuRegisterPairLocation(reg, reg + 1);
439    }
440
441    case Primitive::kPrimVoid:
442      LOG(FATAL) << "Unreachable type " << type;
443  }
444
445  return Location();
446}
447
448void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
449  // Don't allocate the dalvik style register pair passing.
450  blocked_register_pairs_[R1_R2] = true;
451
452  // Stack register, LR and PC are always reserved.
453  blocked_core_registers_[SP] = true;
454  blocked_core_registers_[LR] = true;
455  blocked_core_registers_[PC] = true;
456
457  // Reserve thread register.
458  blocked_core_registers_[TR] = true;
459
460  // Reserve temp register.
461  blocked_core_registers_[IP] = true;
462
463  if (is_baseline) {
464    for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
465      blocked_core_registers_[kCoreCalleeSaves[i]] = true;
466    }
467
468    blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
469
470    for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
471      blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
472    }
473  }
474
475  UpdateBlockedPairRegisters();
476}
477
478void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
479  for (int i = 0; i < kNumberOfRegisterPairs; i++) {
480    ArmManagedRegister current =
481        ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
482    if (blocked_core_registers_[current.AsRegisterPairLow()]
483        || blocked_core_registers_[current.AsRegisterPairHigh()]) {
484      blocked_register_pairs_[i] = true;
485    }
486  }
487}
488
489InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
490      : HGraphVisitor(graph),
491        assembler_(codegen->GetAssembler()),
492        codegen_(codegen) {}
493
494static uint32_t LeastSignificantBit(uint32_t mask) {
495  // ffs starts at 1.
496  return ffs(mask) - 1;
497}
498
499void CodeGeneratorARM::ComputeSpillMask() {
500  core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
501  // Save one extra register for baseline. Note that on thumb2, there is no easy
502  // instruction to restore just the PC, so this actually helps both baseline
503  // and non-baseline to save and restore at least two registers at entry and exit.
504  core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
505  DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
506  fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
507  // We use vpush and vpop for saving and restoring floating point registers, which take
508  // a SRegister and the number of registers to save/restore after that SRegister. We
509  // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
510  // but in the range.
511  if (fpu_spill_mask_ != 0) {
512    uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
513    uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
514    for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
515      fpu_spill_mask_ |= (1 << i);
516    }
517  }
518}
519
520static dwarf::Reg DWARFReg(Register reg) {
521  return dwarf::Reg::ArmCore(static_cast<int>(reg));
522}
523
524static dwarf::Reg DWARFReg(SRegister reg) {
525  return dwarf::Reg::ArmFp(static_cast<int>(reg));
526}
527
528void CodeGeneratorARM::GenerateFrameEntry() {
529  bool skip_overflow_check =
530      IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
531  DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
532  __ Bind(&frame_entry_label_);
533
534  if (HasEmptyFrame()) {
535    return;
536  }
537
538  if (!skip_overflow_check) {
539    __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
540    __ LoadFromOffset(kLoadWord, IP, IP, 0);
541    RecordPcInfo(nullptr, 0);
542  }
543
544  // PC is in the list of callee-save to mimic Quick, but we need to push
545  // LR at entry instead.
546  uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR;
547  __ PushList(push_mask);
548  __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask));
549  __ cfi().RelOffsetForMany(DWARFReg(R0), 0, push_mask, kArmWordSize);
550  if (fpu_spill_mask_ != 0) {
551    SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
552    __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
553    __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
554    __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
555  }
556  int adjust = GetFrameSize() - FrameEntrySpillSize();
557  __ AddConstant(SP, -adjust);
558  __ cfi().AdjustCFAOffset(adjust);
559  __ StoreToOffset(kStoreWord, R0, SP, 0);
560}
561
562void CodeGeneratorARM::GenerateFrameExit() {
563  if (HasEmptyFrame()) {
564    __ bx(LR);
565    return;
566  }
567  __ cfi().RememberState();
568  int adjust = GetFrameSize() - FrameEntrySpillSize();
569  __ AddConstant(SP, adjust);
570  __ cfi().AdjustCFAOffset(-adjust);
571  if (fpu_spill_mask_ != 0) {
572    SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
573    __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
574    __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
575    __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
576  }
577  __ PopList(core_spill_mask_);
578  __ cfi().RestoreState();
579  __ cfi().DefCFAOffset(GetFrameSize());
580}
581
582void CodeGeneratorARM::Bind(HBasicBlock* block) {
583  __ Bind(GetLabelOf(block));
584}
585
586Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
587  switch (load->GetType()) {
588    case Primitive::kPrimLong:
589    case Primitive::kPrimDouble:
590      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
591
592    case Primitive::kPrimInt:
593    case Primitive::kPrimNot:
594    case Primitive::kPrimFloat:
595      return Location::StackSlot(GetStackSlot(load->GetLocal()));
596
597    case Primitive::kPrimBoolean:
598    case Primitive::kPrimByte:
599    case Primitive::kPrimChar:
600    case Primitive::kPrimShort:
601    case Primitive::kPrimVoid:
602      LOG(FATAL) << "Unexpected type " << load->GetType();
603      UNREACHABLE();
604  }
605
606  LOG(FATAL) << "Unreachable";
607  UNREACHABLE();
608}
609
610Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
611  switch (type) {
612    case Primitive::kPrimBoolean:
613    case Primitive::kPrimByte:
614    case Primitive::kPrimChar:
615    case Primitive::kPrimShort:
616    case Primitive::kPrimInt:
617    case Primitive::kPrimNot: {
618      uint32_t index = gp_index_++;
619      uint32_t stack_index = stack_index_++;
620      if (index < calling_convention.GetNumberOfRegisters()) {
621        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
622      } else {
623        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
624      }
625    }
626
627    case Primitive::kPrimLong: {
628      uint32_t index = gp_index_;
629      uint32_t stack_index = stack_index_;
630      gp_index_ += 2;
631      stack_index_ += 2;
632      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
633        if (calling_convention.GetRegisterAt(index) == R1) {
634          // Skip R1, and use R2_R3 instead.
635          gp_index_++;
636          index++;
637        }
638      }
639      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
640        DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
641                  calling_convention.GetRegisterAt(index + 1));
642        return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
643                                              calling_convention.GetRegisterAt(index + 1));
644      } else {
645        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
646      }
647    }
648
649    case Primitive::kPrimFloat: {
650      uint32_t stack_index = stack_index_++;
651      if (float_index_ % 2 == 0) {
652        float_index_ = std::max(double_index_, float_index_);
653      }
654      if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
655        return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
656      } else {
657        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
658      }
659    }
660
661    case Primitive::kPrimDouble: {
662      double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
663      uint32_t stack_index = stack_index_;
664      stack_index_ += 2;
665      if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
666        uint32_t index = double_index_;
667        double_index_ += 2;
668        Location result = Location::FpuRegisterPairLocation(
669          calling_convention.GetFpuRegisterAt(index),
670          calling_convention.GetFpuRegisterAt(index + 1));
671        DCHECK(ExpectedPairLayout(result));
672        return result;
673      } else {
674        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
675      }
676    }
677
678    case Primitive::kPrimVoid:
679      LOG(FATAL) << "Unexpected parameter type " << type;
680      break;
681  }
682  return Location();
683}
684
685Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
686  switch (type) {
687    case Primitive::kPrimBoolean:
688    case Primitive::kPrimByte:
689    case Primitive::kPrimChar:
690    case Primitive::kPrimShort:
691    case Primitive::kPrimInt:
692    case Primitive::kPrimNot: {
693      return Location::RegisterLocation(R0);
694    }
695
696    case Primitive::kPrimFloat: {
697      return Location::FpuRegisterLocation(S0);
698    }
699
700    case Primitive::kPrimLong: {
701      return Location::RegisterPairLocation(R0, R1);
702    }
703
704    case Primitive::kPrimDouble: {
705      return Location::FpuRegisterPairLocation(S0, S1);
706    }
707
708    case Primitive::kPrimVoid:
709      return Location();
710  }
711  UNREACHABLE();
712}
713
714void CodeGeneratorARM::Move32(Location destination, Location source) {
715  if (source.Equals(destination)) {
716    return;
717  }
718  if (destination.IsRegister()) {
719    if (source.IsRegister()) {
720      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
721    } else if (source.IsFpuRegister()) {
722      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
723    } else {
724      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
725    }
726  } else if (destination.IsFpuRegister()) {
727    if (source.IsRegister()) {
728      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
729    } else if (source.IsFpuRegister()) {
730      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
731    } else {
732      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
733    }
734  } else {
735    DCHECK(destination.IsStackSlot()) << destination;
736    if (source.IsRegister()) {
737      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
738    } else if (source.IsFpuRegister()) {
739      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
740    } else {
741      DCHECK(source.IsStackSlot()) << source;
742      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
743      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
744    }
745  }
746}
747
748void CodeGeneratorARM::Move64(Location destination, Location source) {
749  if (source.Equals(destination)) {
750    return;
751  }
752  if (destination.IsRegisterPair()) {
753    if (source.IsRegisterPair()) {
754      EmitParallelMoves(
755          Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
756          Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
757          Primitive::kPrimInt,
758          Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
759          Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
760          Primitive::kPrimInt);
761    } else if (source.IsFpuRegister()) {
762      UNIMPLEMENTED(FATAL);
763    } else {
764      DCHECK(source.IsDoubleStackSlot());
765      DCHECK(ExpectedPairLayout(destination));
766      __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
767                        SP, source.GetStackIndex());
768    }
769  } else if (destination.IsFpuRegisterPair()) {
770    if (source.IsDoubleStackSlot()) {
771      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
772                         SP,
773                         source.GetStackIndex());
774    } else {
775      UNIMPLEMENTED(FATAL);
776    }
777  } else {
778    DCHECK(destination.IsDoubleStackSlot());
779    if (source.IsRegisterPair()) {
780      // No conflict possible, so just do the moves.
781      if (source.AsRegisterPairLow<Register>() == R1) {
782        DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
783        __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
784        __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
785      } else {
786        __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
787                         SP, destination.GetStackIndex());
788      }
789    } else if (source.IsFpuRegisterPair()) {
790      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
791                        SP,
792                        destination.GetStackIndex());
793    } else {
794      DCHECK(source.IsDoubleStackSlot());
795      EmitParallelMoves(
796          Location::StackSlot(source.GetStackIndex()),
797          Location::StackSlot(destination.GetStackIndex()),
798          Primitive::kPrimInt,
799          Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
800          Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
801          Primitive::kPrimInt);
802    }
803  }
804}
805
806void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
807  LocationSummary* locations = instruction->GetLocations();
808  if (locations != nullptr && locations->Out().Equals(location)) {
809    return;
810  }
811
812  if (locations != nullptr && locations->Out().IsConstant()) {
813    HConstant* const_to_move = locations->Out().GetConstant();
814    if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
815      int32_t value = GetInt32ValueOf(const_to_move);
816      if (location.IsRegister()) {
817        __ LoadImmediate(location.AsRegister<Register>(), value);
818      } else {
819        DCHECK(location.IsStackSlot());
820        __ LoadImmediate(IP, value);
821        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
822      }
823    } else {
824      DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
825      int64_t value = const_to_move->AsLongConstant()->GetValue();
826      if (location.IsRegisterPair()) {
827        __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
828        __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
829      } else {
830        DCHECK(location.IsDoubleStackSlot());
831        __ LoadImmediate(IP, Low32Bits(value));
832        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
833        __ LoadImmediate(IP, High32Bits(value));
834        __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
835      }
836    }
837  } else if (instruction->IsLoadLocal()) {
838    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
839    switch (instruction->GetType()) {
840      case Primitive::kPrimBoolean:
841      case Primitive::kPrimByte:
842      case Primitive::kPrimChar:
843      case Primitive::kPrimShort:
844      case Primitive::kPrimInt:
845      case Primitive::kPrimNot:
846      case Primitive::kPrimFloat:
847        Move32(location, Location::StackSlot(stack_slot));
848        break;
849
850      case Primitive::kPrimLong:
851      case Primitive::kPrimDouble:
852        Move64(location, Location::DoubleStackSlot(stack_slot));
853        break;
854
855      default:
856        LOG(FATAL) << "Unexpected type " << instruction->GetType();
857    }
858  } else if (instruction->IsTemporary()) {
859    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
860    if (temp_location.IsStackSlot()) {
861      Move32(location, temp_location);
862    } else {
863      DCHECK(temp_location.IsDoubleStackSlot());
864      Move64(location, temp_location);
865    }
866  } else {
867    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
868    switch (instruction->GetType()) {
869      case Primitive::kPrimBoolean:
870      case Primitive::kPrimByte:
871      case Primitive::kPrimChar:
872      case Primitive::kPrimShort:
873      case Primitive::kPrimNot:
874      case Primitive::kPrimInt:
875      case Primitive::kPrimFloat:
876        Move32(location, locations->Out());
877        break;
878
879      case Primitive::kPrimLong:
880      case Primitive::kPrimDouble:
881        Move64(location, locations->Out());
882        break;
883
884      default:
885        LOG(FATAL) << "Unexpected type " << instruction->GetType();
886    }
887  }
888}
889
890void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
891                                     HInstruction* instruction,
892                                     uint32_t dex_pc,
893                                     SlowPathCode* slow_path) {
894  __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
895  __ blx(LR);
896  RecordPcInfo(instruction, dex_pc, slow_path);
897  DCHECK(instruction->IsSuspendCheck()
898      || instruction->IsBoundsCheck()
899      || instruction->IsNullCheck()
900      || instruction->IsDivZeroCheck()
901      || instruction->GetLocations()->CanCall()
902      || !IsLeafMethod());
903}
904
905void LocationsBuilderARM::VisitGoto(HGoto* got) {
906  got->SetLocations(nullptr);
907}
908
909void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
910  HBasicBlock* successor = got->GetSuccessor();
911  DCHECK(!successor->IsExitBlock());
912
913  HBasicBlock* block = got->GetBlock();
914  HInstruction* previous = got->GetPrevious();
915
916  HLoopInformation* info = block->GetLoopInformation();
917  if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
918    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
919    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
920    return;
921  }
922
923  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
924    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
925  }
926  if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
927    __ b(codegen_->GetLabelOf(successor));
928  }
929}
930
931void LocationsBuilderARM::VisitExit(HExit* exit) {
932  exit->SetLocations(nullptr);
933}
934
935void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
936  UNUSED(exit);
937}
938
939void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
940                                                        Label* true_target,
941                                                        Label* false_target,
942                                                        Label* always_true_target) {
943  HInstruction* cond = instruction->InputAt(0);
944  if (cond->IsIntConstant()) {
945    // Constant condition, statically compared against 1.
946    int32_t cond_value = cond->AsIntConstant()->GetValue();
947    if (cond_value == 1) {
948      if (always_true_target != nullptr) {
949        __ b(always_true_target);
950      }
951      return;
952    } else {
953      DCHECK_EQ(cond_value, 0);
954    }
955  } else {
956    if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
957      // Condition has been materialized, compare the output to 0
958      DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
959      __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
960             ShifterOperand(0));
961      __ b(true_target, NE);
962    } else {
963      // Condition has not been materialized, use its inputs as the
964      // comparison and its condition as the branch condition.
965      LocationSummary* locations = cond->GetLocations();
966      DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
967      Register left = locations->InAt(0).AsRegister<Register>();
968      if (locations->InAt(1).IsRegister()) {
969        __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
970      } else {
971        DCHECK(locations->InAt(1).IsConstant());
972        HConstant* constant = locations->InAt(1).GetConstant();
973        int32_t value = CodeGenerator::GetInt32ValueOf(constant);
974        ShifterOperand operand;
975        if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
976          __ cmp(left, operand);
977        } else {
978          Register temp = IP;
979          __ LoadImmediate(temp, value);
980          __ cmp(left, ShifterOperand(temp));
981        }
982      }
983      __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
984    }
985  }
986  if (false_target != nullptr) {
987    __ b(false_target);
988  }
989}
990
991void LocationsBuilderARM::VisitIf(HIf* if_instr) {
992  LocationSummary* locations =
993      new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
994  HInstruction* cond = if_instr->InputAt(0);
995  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
996    locations->SetInAt(0, Location::RequiresRegister());
997  }
998}
999
1000void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1001  Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1002  Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1003  Label* always_true_target = true_target;
1004  if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1005                                if_instr->IfTrueSuccessor())) {
1006    always_true_target = nullptr;
1007  }
1008  if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1009                                if_instr->IfFalseSuccessor())) {
1010    false_target = nullptr;
1011  }
1012  GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1013}
1014
1015void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1016  LocationSummary* locations = new (GetGraph()->GetArena())
1017      LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1018  HInstruction* cond = deoptimize->InputAt(0);
1019  DCHECK(cond->IsCondition());
1020  if (cond->AsCondition()->NeedsMaterialization()) {
1021    locations->SetInAt(0, Location::RequiresRegister());
1022  }
1023}
1024
1025void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1026  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
1027      DeoptimizationSlowPathARM(deoptimize);
1028  codegen_->AddSlowPath(slow_path);
1029  Label* slow_path_entry = slow_path->GetEntryLabel();
1030  GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1031}
1032
1033void LocationsBuilderARM::VisitCondition(HCondition* comp) {
1034  LocationSummary* locations =
1035      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
1036  locations->SetInAt(0, Location::RequiresRegister());
1037  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
1038  if (comp->NeedsMaterialization()) {
1039    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1040  }
1041}
1042
1043void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
1044  if (!comp->NeedsMaterialization()) return;
1045  LocationSummary* locations = comp->GetLocations();
1046  Register left = locations->InAt(0).AsRegister<Register>();
1047
1048  if (locations->InAt(1).IsRegister()) {
1049    __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
1050  } else {
1051    DCHECK(locations->InAt(1).IsConstant());
1052    int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
1053    ShifterOperand operand;
1054    if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
1055      __ cmp(left, operand);
1056    } else {
1057      Register temp = IP;
1058      __ LoadImmediate(temp, value);
1059      __ cmp(left, ShifterOperand(temp));
1060    }
1061  }
1062  __ it(ARMCondition(comp->GetCondition()), kItElse);
1063  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1064         ARMCondition(comp->GetCondition()));
1065  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1066         ARMOppositeCondition(comp->GetCondition()));
1067}
1068
1069void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1070  VisitCondition(comp);
1071}
1072
1073void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1074  VisitCondition(comp);
1075}
1076
1077void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1078  VisitCondition(comp);
1079}
1080
1081void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1082  VisitCondition(comp);
1083}
1084
1085void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1086  VisitCondition(comp);
1087}
1088
1089void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1090  VisitCondition(comp);
1091}
1092
1093void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1094  VisitCondition(comp);
1095}
1096
1097void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1098  VisitCondition(comp);
1099}
1100
1101void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1102  VisitCondition(comp);
1103}
1104
1105void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1106  VisitCondition(comp);
1107}
1108
1109void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1110  VisitCondition(comp);
1111}
1112
1113void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1114  VisitCondition(comp);
1115}
1116
1117void LocationsBuilderARM::VisitLocal(HLocal* local) {
1118  local->SetLocations(nullptr);
1119}
1120
1121void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1122  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1123}
1124
1125void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
1126  load->SetLocations(nullptr);
1127}
1128
1129void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
1130  // Nothing to do, this is driven by the code generator.
1131  UNUSED(load);
1132}
1133
1134void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
1135  LocationSummary* locations =
1136      new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
1137  switch (store->InputAt(1)->GetType()) {
1138    case Primitive::kPrimBoolean:
1139    case Primitive::kPrimByte:
1140    case Primitive::kPrimChar:
1141    case Primitive::kPrimShort:
1142    case Primitive::kPrimInt:
1143    case Primitive::kPrimNot:
1144    case Primitive::kPrimFloat:
1145      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1146      break;
1147
1148    case Primitive::kPrimLong:
1149    case Primitive::kPrimDouble:
1150      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1151      break;
1152
1153    default:
1154      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
1155  }
1156}
1157
1158void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
1159  UNUSED(store);
1160}
1161
1162void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
1163  LocationSummary* locations =
1164      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1165  locations->SetOut(Location::ConstantLocation(constant));
1166}
1167
1168void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
1169  // Will be generated at use site.
1170  UNUSED(constant);
1171}
1172
1173void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1174  LocationSummary* locations =
1175      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1176  locations->SetOut(Location::ConstantLocation(constant));
1177}
1178
1179void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1180  // Will be generated at use site.
1181  UNUSED(constant);
1182}
1183
1184void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
1185  LocationSummary* locations =
1186      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1187  locations->SetOut(Location::ConstantLocation(constant));
1188}
1189
1190void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1191  // Will be generated at use site.
1192  UNUSED(constant);
1193}
1194
1195void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1196  LocationSummary* locations =
1197      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1198  locations->SetOut(Location::ConstantLocation(constant));
1199}
1200
1201void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1202  // Will be generated at use site.
1203  UNUSED(constant);
1204}
1205
1206void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1207  LocationSummary* locations =
1208      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1209  locations->SetOut(Location::ConstantLocation(constant));
1210}
1211
1212void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1213  // Will be generated at use site.
1214  UNUSED(constant);
1215}
1216
1217void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
1218  ret->SetLocations(nullptr);
1219}
1220
1221void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
1222  UNUSED(ret);
1223  codegen_->GenerateFrameExit();
1224}
1225
1226void LocationsBuilderARM::VisitReturn(HReturn* ret) {
1227  LocationSummary* locations =
1228      new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
1229  locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
1230}
1231
1232void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
1233  UNUSED(ret);
1234  codegen_->GenerateFrameExit();
1235}
1236
1237void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1238  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1239                                         codegen_->GetInstructionSetFeatures());
1240  if (intrinsic.TryDispatch(invoke)) {
1241    return;
1242  }
1243
1244  HandleInvoke(invoke);
1245}
1246
1247void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
1248  DCHECK(RequiresCurrentMethod());
1249  __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
1250}
1251
1252static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1253  if (invoke->GetLocations()->Intrinsified()) {
1254    IntrinsicCodeGeneratorARM intrinsic(codegen);
1255    intrinsic.Dispatch(invoke);
1256    return true;
1257  }
1258  return false;
1259}
1260
1261void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1262  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1263    return;
1264  }
1265
1266  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1267
1268  codegen_->GenerateStaticOrDirectCall(invoke, temp);
1269  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1270}
1271
1272void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
1273  LocationSummary* locations =
1274      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1275  locations->AddTemp(Location::RegisterLocation(R0));
1276
1277  InvokeDexCallingConventionVisitor calling_convention_visitor;
1278  for (size_t i = 0; i < invoke->InputCount(); i++) {
1279    HInstruction* input = invoke->InputAt(i);
1280    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1281  }
1282
1283  locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
1284}
1285
1286void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1287  IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1288                                         codegen_->GetInstructionSetFeatures());
1289  if (intrinsic.TryDispatch(invoke)) {
1290    return;
1291  }
1292
1293  HandleInvoke(invoke);
1294}
1295
1296void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1297  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1298    return;
1299  }
1300
1301  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1302  uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1303          invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1304  LocationSummary* locations = invoke->GetLocations();
1305  Location receiver = locations->InAt(0);
1306  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1307  // temp = object->GetClass();
1308  if (receiver.IsStackSlot()) {
1309    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1310    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1311  } else {
1312    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
1313  }
1314  codegen_->MaybeRecordImplicitNullCheck(invoke);
1315  // temp = temp->GetMethodAt(method_offset);
1316  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1317      kArmWordSize).Int32Value();
1318  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1319  // LR = temp->GetEntryPoint();
1320  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1321  // LR();
1322  __ blx(LR);
1323  DCHECK(!codegen_->IsLeafMethod());
1324  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1325}
1326
1327void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1328  HandleInvoke(invoke);
1329  // Add the hidden argument.
1330  invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1331}
1332
1333void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1334  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1335  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1336  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1337          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1338  LocationSummary* locations = invoke->GetLocations();
1339  Location receiver = locations->InAt(0);
1340  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1341
1342  // Set the hidden argument.
1343  __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1344                   invoke->GetDexMethodIndex());
1345
1346  // temp = object->GetClass();
1347  if (receiver.IsStackSlot()) {
1348    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1349    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1350  } else {
1351    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
1352  }
1353  codegen_->MaybeRecordImplicitNullCheck(invoke);
1354  // temp = temp->GetImtEntryAt(method_offset);
1355  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1356      kArmWordSize).Int32Value();
1357  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1358  // LR = temp->GetEntryPoint();
1359  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1360  // LR();
1361  __ blx(LR);
1362  DCHECK(!codegen_->IsLeafMethod());
1363  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1364}
1365
1366void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1367  LocationSummary* locations =
1368      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1369  switch (neg->GetResultType()) {
1370    case Primitive::kPrimInt: {
1371      locations->SetInAt(0, Location::RequiresRegister());
1372      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1373      break;
1374    }
1375    case Primitive::kPrimLong: {
1376      locations->SetInAt(0, Location::RequiresRegister());
1377      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1378      break;
1379    }
1380
1381    case Primitive::kPrimFloat:
1382    case Primitive::kPrimDouble:
1383      locations->SetInAt(0, Location::RequiresFpuRegister());
1384      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1385      break;
1386
1387    default:
1388      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1389  }
1390}
1391
1392void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1393  LocationSummary* locations = neg->GetLocations();
1394  Location out = locations->Out();
1395  Location in = locations->InAt(0);
1396  switch (neg->GetResultType()) {
1397    case Primitive::kPrimInt:
1398      DCHECK(in.IsRegister());
1399      __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
1400      break;
1401
1402    case Primitive::kPrimLong:
1403      DCHECK(in.IsRegisterPair());
1404      // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1405      __ rsbs(out.AsRegisterPairLow<Register>(),
1406              in.AsRegisterPairLow<Register>(),
1407              ShifterOperand(0));
1408      // We cannot emit an RSC (Reverse Subtract with Carry)
1409      // instruction here, as it does not exist in the Thumb-2
1410      // instruction set.  We use the following approach
1411      // using SBC and SUB instead.
1412      //
1413      // out.hi = -C
1414      __ sbc(out.AsRegisterPairHigh<Register>(),
1415             out.AsRegisterPairHigh<Register>(),
1416             ShifterOperand(out.AsRegisterPairHigh<Register>()));
1417      // out.hi = out.hi - in.hi
1418      __ sub(out.AsRegisterPairHigh<Register>(),
1419             out.AsRegisterPairHigh<Register>(),
1420             ShifterOperand(in.AsRegisterPairHigh<Register>()));
1421      break;
1422
1423    case Primitive::kPrimFloat:
1424      DCHECK(in.IsFpuRegister());
1425      __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
1426      break;
1427
1428    case Primitive::kPrimDouble:
1429      DCHECK(in.IsFpuRegisterPair());
1430      __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1431               FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1432      break;
1433
1434    default:
1435      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1436  }
1437}
1438
1439void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
1440  Primitive::Type result_type = conversion->GetResultType();
1441  Primitive::Type input_type = conversion->GetInputType();
1442  DCHECK_NE(result_type, input_type);
1443
1444  // The float-to-long and double-to-long type conversions rely on a
1445  // call to the runtime.
1446  LocationSummary::CallKind call_kind =
1447      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1448       && result_type == Primitive::kPrimLong)
1449      ? LocationSummary::kCall
1450      : LocationSummary::kNoCall;
1451  LocationSummary* locations =
1452      new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1453
1454  // The Java language does not allow treating boolean as an integral type but
1455  // our bit representation makes it safe.
1456
1457  switch (result_type) {
1458    case Primitive::kPrimByte:
1459      switch (input_type) {
1460        case Primitive::kPrimBoolean:
1461          // Boolean input is a result of code transformations.
1462        case Primitive::kPrimShort:
1463        case Primitive::kPrimInt:
1464        case Primitive::kPrimChar:
1465          // Processing a Dex `int-to-byte' instruction.
1466          locations->SetInAt(0, Location::RequiresRegister());
1467          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1468          break;
1469
1470        default:
1471          LOG(FATAL) << "Unexpected type conversion from " << input_type
1472                     << " to " << result_type;
1473      }
1474      break;
1475
1476    case Primitive::kPrimShort:
1477      switch (input_type) {
1478        case Primitive::kPrimBoolean:
1479          // Boolean input is a result of code transformations.
1480        case Primitive::kPrimByte:
1481        case Primitive::kPrimInt:
1482        case Primitive::kPrimChar:
1483          // Processing a Dex `int-to-short' instruction.
1484          locations->SetInAt(0, Location::RequiresRegister());
1485          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1486          break;
1487
1488        default:
1489          LOG(FATAL) << "Unexpected type conversion from " << input_type
1490                     << " to " << result_type;
1491      }
1492      break;
1493
1494    case Primitive::kPrimInt:
1495      switch (input_type) {
1496        case Primitive::kPrimLong:
1497          // Processing a Dex `long-to-int' instruction.
1498          locations->SetInAt(0, Location::Any());
1499          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1500          break;
1501
1502        case Primitive::kPrimFloat:
1503          // Processing a Dex `float-to-int' instruction.
1504          locations->SetInAt(0, Location::RequiresFpuRegister());
1505          locations->SetOut(Location::RequiresRegister());
1506          locations->AddTemp(Location::RequiresFpuRegister());
1507          break;
1508
1509        case Primitive::kPrimDouble:
1510          // Processing a Dex `double-to-int' instruction.
1511          locations->SetInAt(0, Location::RequiresFpuRegister());
1512          locations->SetOut(Location::RequiresRegister());
1513          locations->AddTemp(Location::RequiresFpuRegister());
1514          break;
1515
1516        default:
1517          LOG(FATAL) << "Unexpected type conversion from " << input_type
1518                     << " to " << result_type;
1519      }
1520      break;
1521
1522    case Primitive::kPrimLong:
1523      switch (input_type) {
1524        case Primitive::kPrimBoolean:
1525          // Boolean input is a result of code transformations.
1526        case Primitive::kPrimByte:
1527        case Primitive::kPrimShort:
1528        case Primitive::kPrimInt:
1529        case Primitive::kPrimChar:
1530          // Processing a Dex `int-to-long' instruction.
1531          locations->SetInAt(0, Location::RequiresRegister());
1532          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1533          break;
1534
1535        case Primitive::kPrimFloat: {
1536          // Processing a Dex `float-to-long' instruction.
1537          InvokeRuntimeCallingConvention calling_convention;
1538          locations->SetInAt(0, Location::FpuRegisterLocation(
1539              calling_convention.GetFpuRegisterAt(0)));
1540          locations->SetOut(Location::RegisterPairLocation(R0, R1));
1541          break;
1542        }
1543
1544        case Primitive::kPrimDouble: {
1545          // Processing a Dex `double-to-long' instruction.
1546          InvokeRuntimeCallingConvention calling_convention;
1547          locations->SetInAt(0, Location::FpuRegisterPairLocation(
1548              calling_convention.GetFpuRegisterAt(0),
1549              calling_convention.GetFpuRegisterAt(1)));
1550          locations->SetOut(Location::RegisterPairLocation(R0, R1));
1551          break;
1552        }
1553
1554        default:
1555          LOG(FATAL) << "Unexpected type conversion from " << input_type
1556                     << " to " << result_type;
1557      }
1558      break;
1559
1560    case Primitive::kPrimChar:
1561      switch (input_type) {
1562        case Primitive::kPrimBoolean:
1563          // Boolean input is a result of code transformations.
1564        case Primitive::kPrimByte:
1565        case Primitive::kPrimShort:
1566        case Primitive::kPrimInt:
1567          // Processing a Dex `int-to-char' instruction.
1568          locations->SetInAt(0, Location::RequiresRegister());
1569          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1570          break;
1571
1572        default:
1573          LOG(FATAL) << "Unexpected type conversion from " << input_type
1574                     << " to " << result_type;
1575      }
1576      break;
1577
1578    case Primitive::kPrimFloat:
1579      switch (input_type) {
1580        case Primitive::kPrimBoolean:
1581          // Boolean input is a result of code transformations.
1582        case Primitive::kPrimByte:
1583        case Primitive::kPrimShort:
1584        case Primitive::kPrimInt:
1585        case Primitive::kPrimChar:
1586          // Processing a Dex `int-to-float' instruction.
1587          locations->SetInAt(0, Location::RequiresRegister());
1588          locations->SetOut(Location::RequiresFpuRegister());
1589          break;
1590
1591        case Primitive::kPrimLong:
1592          // Processing a Dex `long-to-float' instruction.
1593          locations->SetInAt(0, Location::RequiresRegister());
1594          locations->SetOut(Location::RequiresFpuRegister());
1595          locations->AddTemp(Location::RequiresRegister());
1596          locations->AddTemp(Location::RequiresRegister());
1597          locations->AddTemp(Location::RequiresFpuRegister());
1598          locations->AddTemp(Location::RequiresFpuRegister());
1599          break;
1600
1601        case Primitive::kPrimDouble:
1602          // Processing a Dex `double-to-float' instruction.
1603          locations->SetInAt(0, Location::RequiresFpuRegister());
1604          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1605          break;
1606
1607        default:
1608          LOG(FATAL) << "Unexpected type conversion from " << input_type
1609                     << " to " << result_type;
1610      };
1611      break;
1612
1613    case Primitive::kPrimDouble:
1614      switch (input_type) {
1615        case Primitive::kPrimBoolean:
1616          // Boolean input is a result of code transformations.
1617        case Primitive::kPrimByte:
1618        case Primitive::kPrimShort:
1619        case Primitive::kPrimInt:
1620        case Primitive::kPrimChar:
1621          // Processing a Dex `int-to-double' instruction.
1622          locations->SetInAt(0, Location::RequiresRegister());
1623          locations->SetOut(Location::RequiresFpuRegister());
1624          break;
1625
1626        case Primitive::kPrimLong:
1627          // Processing a Dex `long-to-double' instruction.
1628          locations->SetInAt(0, Location::RequiresRegister());
1629          locations->SetOut(Location::RequiresFpuRegister());
1630          locations->AddTemp(Location::RequiresRegister());
1631          locations->AddTemp(Location::RequiresRegister());
1632          locations->AddTemp(Location::RequiresFpuRegister());
1633          break;
1634
1635        case Primitive::kPrimFloat:
1636          // Processing a Dex `float-to-double' instruction.
1637          locations->SetInAt(0, Location::RequiresFpuRegister());
1638          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1639          break;
1640
1641        default:
1642          LOG(FATAL) << "Unexpected type conversion from " << input_type
1643                     << " to " << result_type;
1644      };
1645      break;
1646
1647    default:
1648      LOG(FATAL) << "Unexpected type conversion from " << input_type
1649                 << " to " << result_type;
1650  }
1651}
1652
1653void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1654  LocationSummary* locations = conversion->GetLocations();
1655  Location out = locations->Out();
1656  Location in = locations->InAt(0);
1657  Primitive::Type result_type = conversion->GetResultType();
1658  Primitive::Type input_type = conversion->GetInputType();
1659  DCHECK_NE(result_type, input_type);
1660  switch (result_type) {
1661    case Primitive::kPrimByte:
1662      switch (input_type) {
1663        case Primitive::kPrimBoolean:
1664          // Boolean input is a result of code transformations.
1665        case Primitive::kPrimShort:
1666        case Primitive::kPrimInt:
1667        case Primitive::kPrimChar:
1668          // Processing a Dex `int-to-byte' instruction.
1669          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
1670          break;
1671
1672        default:
1673          LOG(FATAL) << "Unexpected type conversion from " << input_type
1674                     << " to " << result_type;
1675      }
1676      break;
1677
1678    case Primitive::kPrimShort:
1679      switch (input_type) {
1680        case Primitive::kPrimBoolean:
1681          // Boolean input is a result of code transformations.
1682        case Primitive::kPrimByte:
1683        case Primitive::kPrimInt:
1684        case Primitive::kPrimChar:
1685          // Processing a Dex `int-to-short' instruction.
1686          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
1687          break;
1688
1689        default:
1690          LOG(FATAL) << "Unexpected type conversion from " << input_type
1691                     << " to " << result_type;
1692      }
1693      break;
1694
1695    case Primitive::kPrimInt:
1696      switch (input_type) {
1697        case Primitive::kPrimLong:
1698          // Processing a Dex `long-to-int' instruction.
1699          DCHECK(out.IsRegister());
1700          if (in.IsRegisterPair()) {
1701            __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
1702          } else if (in.IsDoubleStackSlot()) {
1703            __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
1704          } else {
1705            DCHECK(in.IsConstant());
1706            DCHECK(in.GetConstant()->IsLongConstant());
1707            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
1708            __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
1709          }
1710          break;
1711
1712        case Primitive::kPrimFloat: {
1713          // Processing a Dex `float-to-int' instruction.
1714          SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1715          __ vmovs(temp, in.AsFpuRegister<SRegister>());
1716          __ vcvtis(temp, temp);
1717          __ vmovrs(out.AsRegister<Register>(), temp);
1718          break;
1719        }
1720
1721        case Primitive::kPrimDouble: {
1722          // Processing a Dex `double-to-int' instruction.
1723          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1724          DRegister temp_d = FromLowSToD(temp_s);
1725          __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1726          __ vcvtid(temp_s, temp_d);
1727          __ vmovrs(out.AsRegister<Register>(), temp_s);
1728          break;
1729        }
1730
1731        default:
1732          LOG(FATAL) << "Unexpected type conversion from " << input_type
1733                     << " to " << result_type;
1734      }
1735      break;
1736
1737    case Primitive::kPrimLong:
1738      switch (input_type) {
1739        case Primitive::kPrimBoolean:
1740          // Boolean input is a result of code transformations.
1741        case Primitive::kPrimByte:
1742        case Primitive::kPrimShort:
1743        case Primitive::kPrimInt:
1744        case Primitive::kPrimChar:
1745          // Processing a Dex `int-to-long' instruction.
1746          DCHECK(out.IsRegisterPair());
1747          DCHECK(in.IsRegister());
1748          __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
1749          // Sign extension.
1750          __ Asr(out.AsRegisterPairHigh<Register>(),
1751                 out.AsRegisterPairLow<Register>(),
1752                 31);
1753          break;
1754
1755        case Primitive::kPrimFloat:
1756          // Processing a Dex `float-to-long' instruction.
1757          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1758                                  conversion,
1759                                  conversion->GetDexPc(),
1760                                  nullptr);
1761          break;
1762
1763        case Primitive::kPrimDouble:
1764          // Processing a Dex `double-to-long' instruction.
1765          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1766                                  conversion,
1767                                  conversion->GetDexPc(),
1768                                  nullptr);
1769          break;
1770
1771        default:
1772          LOG(FATAL) << "Unexpected type conversion from " << input_type
1773                     << " to " << result_type;
1774      }
1775      break;
1776
1777    case Primitive::kPrimChar:
1778      switch (input_type) {
1779        case Primitive::kPrimBoolean:
1780          // Boolean input is a result of code transformations.
1781        case Primitive::kPrimByte:
1782        case Primitive::kPrimShort:
1783        case Primitive::kPrimInt:
1784          // Processing a Dex `int-to-char' instruction.
1785          __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
1786          break;
1787
1788        default:
1789          LOG(FATAL) << "Unexpected type conversion from " << input_type
1790                     << " to " << result_type;
1791      }
1792      break;
1793
1794    case Primitive::kPrimFloat:
1795      switch (input_type) {
1796        case Primitive::kPrimBoolean:
1797          // Boolean input is a result of code transformations.
1798        case Primitive::kPrimByte:
1799        case Primitive::kPrimShort:
1800        case Primitive::kPrimInt:
1801        case Primitive::kPrimChar: {
1802          // Processing a Dex `int-to-float' instruction.
1803          __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1804          __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
1805          break;
1806        }
1807
1808        case Primitive::kPrimLong: {
1809          // Processing a Dex `long-to-float' instruction.
1810          Register low = in.AsRegisterPairLow<Register>();
1811          Register high = in.AsRegisterPairHigh<Register>();
1812          SRegister output = out.AsFpuRegister<SRegister>();
1813          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1814          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1815          SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1816          DRegister temp1_d = FromLowSToD(temp1_s);
1817          SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
1818          DRegister temp2_d = FromLowSToD(temp2_s);
1819
1820          // Operations use doubles for precision reasons (each 32-bit
1821          // half of a long fits in the 53-bit mantissa of a double,
1822          // but not in the 24-bit mantissa of a float).  This is
1823          // especially important for the low bits.  The result is
1824          // eventually converted to float.
1825
1826          // temp1_d = int-to-double(high)
1827          __ vmovsr(temp1_s, high);
1828          __ vcvtdi(temp1_d, temp1_s);
1829          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1830          // as an immediate value into `temp2_d` does not work, as
1831          // this instruction only transfers 8 significant bits of its
1832          // immediate operand.  Instead, use two 32-bit core
1833          // registers to load `k2Pow32EncodingForDouble` into
1834          // `temp2_d`.
1835          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1836          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1837          __ vmovdrr(temp2_d, constant_low, constant_high);
1838          // temp1_d = temp1_d * 2^32
1839          __ vmuld(temp1_d, temp1_d, temp2_d);
1840          // temp2_d = unsigned-to-double(low)
1841          __ vmovsr(temp2_s, low);
1842          __ vcvtdu(temp2_d, temp2_s);
1843          // temp1_d = temp1_d + temp2_d
1844          __ vaddd(temp1_d, temp1_d, temp2_d);
1845          // output = double-to-float(temp1_d);
1846          __ vcvtsd(output, temp1_d);
1847          break;
1848        }
1849
1850        case Primitive::kPrimDouble:
1851          // Processing a Dex `double-to-float' instruction.
1852          __ vcvtsd(out.AsFpuRegister<SRegister>(),
1853                    FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1854          break;
1855
1856        default:
1857          LOG(FATAL) << "Unexpected type conversion from " << input_type
1858                     << " to " << result_type;
1859      };
1860      break;
1861
1862    case Primitive::kPrimDouble:
1863      switch (input_type) {
1864        case Primitive::kPrimBoolean:
1865          // Boolean input is a result of code transformations.
1866        case Primitive::kPrimByte:
1867        case Primitive::kPrimShort:
1868        case Primitive::kPrimInt:
1869        case Primitive::kPrimChar: {
1870          // Processing a Dex `int-to-double' instruction.
1871          __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
1872          __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1873                    out.AsFpuRegisterPairLow<SRegister>());
1874          break;
1875        }
1876
1877        case Primitive::kPrimLong: {
1878          // Processing a Dex `long-to-double' instruction.
1879          Register low = in.AsRegisterPairLow<Register>();
1880          Register high = in.AsRegisterPairHigh<Register>();
1881          SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1882          DRegister out_d = FromLowSToD(out_s);
1883          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1884          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1885          SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1886          DRegister temp_d = FromLowSToD(temp_s);
1887
1888          // out_d = int-to-double(high)
1889          __ vmovsr(out_s, high);
1890          __ vcvtdi(out_d, out_s);
1891          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1892          // as an immediate value into `temp_d` does not work, as
1893          // this instruction only transfers 8 significant bits of its
1894          // immediate operand.  Instead, use two 32-bit core
1895          // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
1896          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1897          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1898          __ vmovdrr(temp_d, constant_low, constant_high);
1899          // out_d = out_d * 2^32
1900          __ vmuld(out_d, out_d, temp_d);
1901          // temp_d = unsigned-to-double(low)
1902          __ vmovsr(temp_s, low);
1903          __ vcvtdu(temp_d, temp_s);
1904          // out_d = out_d + temp_d
1905          __ vaddd(out_d, out_d, temp_d);
1906          break;
1907        }
1908
1909        case Primitive::kPrimFloat:
1910          // Processing a Dex `float-to-double' instruction.
1911          __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1912                    in.AsFpuRegister<SRegister>());
1913          break;
1914
1915        default:
1916          LOG(FATAL) << "Unexpected type conversion from " << input_type
1917                     << " to " << result_type;
1918      };
1919      break;
1920
1921    default:
1922      LOG(FATAL) << "Unexpected type conversion from " << input_type
1923                 << " to " << result_type;
1924  }
1925}
1926
1927void LocationsBuilderARM::VisitAdd(HAdd* add) {
1928  LocationSummary* locations =
1929      new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
1930  switch (add->GetResultType()) {
1931    case Primitive::kPrimInt: {
1932      locations->SetInAt(0, Location::RequiresRegister());
1933      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1934      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1935      break;
1936    }
1937
1938    case Primitive::kPrimLong: {
1939      locations->SetInAt(0, Location::RequiresRegister());
1940      locations->SetInAt(1, Location::RequiresRegister());
1941      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1942      break;
1943    }
1944
1945    case Primitive::kPrimFloat:
1946    case Primitive::kPrimDouble: {
1947      locations->SetInAt(0, Location::RequiresFpuRegister());
1948      locations->SetInAt(1, Location::RequiresFpuRegister());
1949      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1950      break;
1951    }
1952
1953    default:
1954      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1955  }
1956}
1957
1958void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1959  LocationSummary* locations = add->GetLocations();
1960  Location out = locations->Out();
1961  Location first = locations->InAt(0);
1962  Location second = locations->InAt(1);
1963  switch (add->GetResultType()) {
1964    case Primitive::kPrimInt:
1965      if (second.IsRegister()) {
1966        __ add(out.AsRegister<Register>(),
1967               first.AsRegister<Register>(),
1968               ShifterOperand(second.AsRegister<Register>()));
1969      } else {
1970        __ AddConstant(out.AsRegister<Register>(),
1971                       first.AsRegister<Register>(),
1972                       second.GetConstant()->AsIntConstant()->GetValue());
1973      }
1974      break;
1975
1976    case Primitive::kPrimLong: {
1977      DCHECK(second.IsRegisterPair());
1978      __ adds(out.AsRegisterPairLow<Register>(),
1979              first.AsRegisterPairLow<Register>(),
1980              ShifterOperand(second.AsRegisterPairLow<Register>()));
1981      __ adc(out.AsRegisterPairHigh<Register>(),
1982             first.AsRegisterPairHigh<Register>(),
1983             ShifterOperand(second.AsRegisterPairHigh<Register>()));
1984      break;
1985    }
1986
1987    case Primitive::kPrimFloat:
1988      __ vadds(out.AsFpuRegister<SRegister>(),
1989               first.AsFpuRegister<SRegister>(),
1990               second.AsFpuRegister<SRegister>());
1991      break;
1992
1993    case Primitive::kPrimDouble:
1994      __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1995               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1996               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
1997      break;
1998
1999    default:
2000      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2001  }
2002}
2003
2004void LocationsBuilderARM::VisitSub(HSub* sub) {
2005  LocationSummary* locations =
2006      new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
2007  switch (sub->GetResultType()) {
2008    case Primitive::kPrimInt: {
2009      locations->SetInAt(0, Location::RequiresRegister());
2010      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
2011      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2012      break;
2013    }
2014
2015    case Primitive::kPrimLong: {
2016      locations->SetInAt(0, Location::RequiresRegister());
2017      locations->SetInAt(1, Location::RequiresRegister());
2018      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2019      break;
2020    }
2021    case Primitive::kPrimFloat:
2022    case Primitive::kPrimDouble: {
2023      locations->SetInAt(0, Location::RequiresFpuRegister());
2024      locations->SetInAt(1, Location::RequiresFpuRegister());
2025      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2026      break;
2027    }
2028    default:
2029      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2030  }
2031}
2032
2033void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2034  LocationSummary* locations = sub->GetLocations();
2035  Location out = locations->Out();
2036  Location first = locations->InAt(0);
2037  Location second = locations->InAt(1);
2038  switch (sub->GetResultType()) {
2039    case Primitive::kPrimInt: {
2040      if (second.IsRegister()) {
2041        __ sub(out.AsRegister<Register>(),
2042               first.AsRegister<Register>(),
2043               ShifterOperand(second.AsRegister<Register>()));
2044      } else {
2045        __ AddConstant(out.AsRegister<Register>(),
2046                       first.AsRegister<Register>(),
2047                       -second.GetConstant()->AsIntConstant()->GetValue());
2048      }
2049      break;
2050    }
2051
2052    case Primitive::kPrimLong: {
2053      DCHECK(second.IsRegisterPair());
2054      __ subs(out.AsRegisterPairLow<Register>(),
2055              first.AsRegisterPairLow<Register>(),
2056              ShifterOperand(second.AsRegisterPairLow<Register>()));
2057      __ sbc(out.AsRegisterPairHigh<Register>(),
2058             first.AsRegisterPairHigh<Register>(),
2059             ShifterOperand(second.AsRegisterPairHigh<Register>()));
2060      break;
2061    }
2062
2063    case Primitive::kPrimFloat: {
2064      __ vsubs(out.AsFpuRegister<SRegister>(),
2065               first.AsFpuRegister<SRegister>(),
2066               second.AsFpuRegister<SRegister>());
2067      break;
2068    }
2069
2070    case Primitive::kPrimDouble: {
2071      __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2072               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2073               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2074      break;
2075    }
2076
2077
2078    default:
2079      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
2080  }
2081}
2082
2083void LocationsBuilderARM::VisitMul(HMul* mul) {
2084  LocationSummary* locations =
2085      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2086  switch (mul->GetResultType()) {
2087    case Primitive::kPrimInt:
2088    case Primitive::kPrimLong:  {
2089      locations->SetInAt(0, Location::RequiresRegister());
2090      locations->SetInAt(1, Location::RequiresRegister());
2091      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2092      break;
2093    }
2094
2095    case Primitive::kPrimFloat:
2096    case Primitive::kPrimDouble: {
2097      locations->SetInAt(0, Location::RequiresFpuRegister());
2098      locations->SetInAt(1, Location::RequiresFpuRegister());
2099      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2100      break;
2101    }
2102
2103    default:
2104      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2105  }
2106}
2107
2108void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2109  LocationSummary* locations = mul->GetLocations();
2110  Location out = locations->Out();
2111  Location first = locations->InAt(0);
2112  Location second = locations->InAt(1);
2113  switch (mul->GetResultType()) {
2114    case Primitive::kPrimInt: {
2115      __ mul(out.AsRegister<Register>(),
2116             first.AsRegister<Register>(),
2117             second.AsRegister<Register>());
2118      break;
2119    }
2120    case Primitive::kPrimLong: {
2121      Register out_hi = out.AsRegisterPairHigh<Register>();
2122      Register out_lo = out.AsRegisterPairLow<Register>();
2123      Register in1_hi = first.AsRegisterPairHigh<Register>();
2124      Register in1_lo = first.AsRegisterPairLow<Register>();
2125      Register in2_hi = second.AsRegisterPairHigh<Register>();
2126      Register in2_lo = second.AsRegisterPairLow<Register>();
2127
2128      // Extra checks to protect caused by the existence of R1_R2.
2129      // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2130      // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2131      DCHECK_NE(out_hi, in1_lo);
2132      DCHECK_NE(out_hi, in2_lo);
2133
2134      // input: in1 - 64 bits, in2 - 64 bits
2135      // output: out
2136      // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2137      // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2138      // parts: out.lo = (in1.lo * in2.lo)[31:0]
2139
2140      // IP <- in1.lo * in2.hi
2141      __ mul(IP, in1_lo, in2_hi);
2142      // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2143      __ mla(out_hi, in1_hi, in2_lo, IP);
2144      // out.lo <- (in1.lo * in2.lo)[31:0];
2145      __ umull(out_lo, IP, in1_lo, in2_lo);
2146      // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2147      __ add(out_hi, out_hi, ShifterOperand(IP));
2148      break;
2149    }
2150
2151    case Primitive::kPrimFloat: {
2152      __ vmuls(out.AsFpuRegister<SRegister>(),
2153               first.AsFpuRegister<SRegister>(),
2154               second.AsFpuRegister<SRegister>());
2155      break;
2156    }
2157
2158    case Primitive::kPrimDouble: {
2159      __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2160               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2161               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2162      break;
2163    }
2164
2165    default:
2166      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2167  }
2168}
2169
2170void LocationsBuilderARM::VisitDiv(HDiv* div) {
2171  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2172  if (div->GetResultType() == Primitive::kPrimLong) {
2173    // pLdiv runtime call.
2174    call_kind = LocationSummary::kCall;
2175  } else if (div->GetResultType() == Primitive::kPrimInt &&
2176             !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2177    // pIdivmod runtime call.
2178    call_kind = LocationSummary::kCall;
2179  }
2180
2181  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2182
2183  switch (div->GetResultType()) {
2184    case Primitive::kPrimInt: {
2185      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2186        locations->SetInAt(0, Location::RequiresRegister());
2187        locations->SetInAt(1, Location::RequiresRegister());
2188        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2189      } else {
2190        InvokeRuntimeCallingConvention calling_convention;
2191        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2192        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2193        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2194        //       we only need the former.
2195        locations->SetOut(Location::RegisterLocation(R0));
2196      }
2197      break;
2198    }
2199    case Primitive::kPrimLong: {
2200      InvokeRuntimeCallingConvention calling_convention;
2201      locations->SetInAt(0, Location::RegisterPairLocation(
2202          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2203      locations->SetInAt(1, Location::RegisterPairLocation(
2204          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2205      locations->SetOut(Location::RegisterPairLocation(R0, R1));
2206      break;
2207    }
2208    case Primitive::kPrimFloat:
2209    case Primitive::kPrimDouble: {
2210      locations->SetInAt(0, Location::RequiresFpuRegister());
2211      locations->SetInAt(1, Location::RequiresFpuRegister());
2212      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2213      break;
2214    }
2215
2216    default:
2217      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2218  }
2219}
2220
2221void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2222  LocationSummary* locations = div->GetLocations();
2223  Location out = locations->Out();
2224  Location first = locations->InAt(0);
2225  Location second = locations->InAt(1);
2226
2227  switch (div->GetResultType()) {
2228    case Primitive::kPrimInt: {
2229      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2230        __ sdiv(out.AsRegister<Register>(),
2231                first.AsRegister<Register>(),
2232                second.AsRegister<Register>());
2233      } else {
2234        InvokeRuntimeCallingConvention calling_convention;
2235        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2236        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2237        DCHECK_EQ(R0, out.AsRegister<Register>());
2238
2239        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2240      }
2241      break;
2242    }
2243
2244    case Primitive::kPrimLong: {
2245      InvokeRuntimeCallingConvention calling_convention;
2246      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2247      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2248      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2249      DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2250      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
2251      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
2252
2253      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
2254      break;
2255    }
2256
2257    case Primitive::kPrimFloat: {
2258      __ vdivs(out.AsFpuRegister<SRegister>(),
2259               first.AsFpuRegister<SRegister>(),
2260               second.AsFpuRegister<SRegister>());
2261      break;
2262    }
2263
2264    case Primitive::kPrimDouble: {
2265      __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2266               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2267               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2268      break;
2269    }
2270
2271    default:
2272      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2273  }
2274}
2275
2276void LocationsBuilderARM::VisitRem(HRem* rem) {
2277  Primitive::Type type = rem->GetResultType();
2278
2279  // Most remainders are implemented in the runtime.
2280  LocationSummary::CallKind call_kind = LocationSummary::kCall;
2281  if (rem->GetResultType() == Primitive::kPrimInt &&
2282      codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2283    // Have hardware divide instruction for int, do it with three instructions.
2284    call_kind = LocationSummary::kNoCall;
2285  }
2286
2287  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2288
2289  switch (type) {
2290    case Primitive::kPrimInt: {
2291      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2292        locations->SetInAt(0, Location::RequiresRegister());
2293        locations->SetInAt(1, Location::RequiresRegister());
2294        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2295        locations->AddTemp(Location::RequiresRegister());
2296      } else {
2297        InvokeRuntimeCallingConvention calling_convention;
2298        locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2299        locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2300        // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2301        //       we only need the latter.
2302        locations->SetOut(Location::RegisterLocation(R1));
2303      }
2304      break;
2305    }
2306    case Primitive::kPrimLong: {
2307      InvokeRuntimeCallingConvention calling_convention;
2308      locations->SetInAt(0, Location::RegisterPairLocation(
2309          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2310      locations->SetInAt(1, Location::RegisterPairLocation(
2311          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2312      // The runtime helper puts the output in R2,R3.
2313      locations->SetOut(Location::RegisterPairLocation(R2, R3));
2314      break;
2315    }
2316    case Primitive::kPrimFloat: {
2317      InvokeRuntimeCallingConvention calling_convention;
2318      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2319      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2320      locations->SetOut(Location::FpuRegisterLocation(S0));
2321      break;
2322    }
2323
2324    case Primitive::kPrimDouble: {
2325      InvokeRuntimeCallingConvention calling_convention;
2326      locations->SetInAt(0, Location::FpuRegisterPairLocation(
2327          calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2328      locations->SetInAt(1, Location::FpuRegisterPairLocation(
2329          calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2330      locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
2331      break;
2332    }
2333
2334    default:
2335      LOG(FATAL) << "Unexpected rem type " << type;
2336  }
2337}
2338
2339void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2340  LocationSummary* locations = rem->GetLocations();
2341  Location out = locations->Out();
2342  Location first = locations->InAt(0);
2343  Location second = locations->InAt(1);
2344
2345  Primitive::Type type = rem->GetResultType();
2346  switch (type) {
2347    case Primitive::kPrimInt: {
2348      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2349        Register reg1 = first.AsRegister<Register>();
2350        Register reg2 = second.AsRegister<Register>();
2351        Register temp = locations->GetTemp(0).AsRegister<Register>();
2352
2353        // temp = reg1 / reg2  (integer division)
2354        // temp = temp * reg2
2355        // dest = reg1 - temp
2356        __ sdiv(temp, reg1, reg2);
2357        __ mul(temp, temp, reg2);
2358        __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2359      } else {
2360        InvokeRuntimeCallingConvention calling_convention;
2361        DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2362        DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2363        DCHECK_EQ(R1, out.AsRegister<Register>());
2364
2365        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2366      }
2367      break;
2368    }
2369
2370    case Primitive::kPrimLong: {
2371      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
2372      break;
2373    }
2374
2375    case Primitive::kPrimFloat: {
2376      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
2377      break;
2378    }
2379
2380    case Primitive::kPrimDouble: {
2381      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
2382      break;
2383    }
2384
2385    default:
2386      LOG(FATAL) << "Unexpected rem type " << type;
2387  }
2388}
2389
2390void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2391  LocationSummary* locations =
2392      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2393  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2394  if (instruction->HasUses()) {
2395    locations->SetOut(Location::SameAsFirstInput());
2396  }
2397}
2398
2399void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2400  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2401  codegen_->AddSlowPath(slow_path);
2402
2403  LocationSummary* locations = instruction->GetLocations();
2404  Location value = locations->InAt(0);
2405
2406  switch (instruction->GetType()) {
2407    case Primitive::kPrimInt: {
2408      if (value.IsRegister()) {
2409        __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
2410        __ b(slow_path->GetEntryLabel(), EQ);
2411      } else {
2412        DCHECK(value.IsConstant()) << value;
2413        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2414          __ b(slow_path->GetEntryLabel());
2415        }
2416      }
2417      break;
2418    }
2419    case Primitive::kPrimLong: {
2420      if (value.IsRegisterPair()) {
2421        __ orrs(IP,
2422                value.AsRegisterPairLow<Register>(),
2423                ShifterOperand(value.AsRegisterPairHigh<Register>()));
2424        __ b(slow_path->GetEntryLabel(), EQ);
2425      } else {
2426        DCHECK(value.IsConstant()) << value;
2427        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2428          __ b(slow_path->GetEntryLabel());
2429        }
2430      }
2431      break;
2432    default:
2433      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2434    }
2435  }
2436}
2437
2438void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2439  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2440
2441  LocationSummary* locations =
2442      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2443
2444  switch (op->GetResultType()) {
2445    case Primitive::kPrimInt: {
2446      locations->SetInAt(0, Location::RequiresRegister());
2447      locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
2448      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2449      break;
2450    }
2451    case Primitive::kPrimLong: {
2452      locations->SetInAt(0, Location::RequiresRegister());
2453      locations->SetInAt(1, Location::RequiresRegister());
2454      locations->AddTemp(Location::RequiresRegister());
2455      locations->SetOut(Location::RequiresRegister());
2456      break;
2457    }
2458    default:
2459      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2460  }
2461}
2462
2463void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2464  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2465
2466  LocationSummary* locations = op->GetLocations();
2467  Location out = locations->Out();
2468  Location first = locations->InAt(0);
2469  Location second = locations->InAt(1);
2470
2471  Primitive::Type type = op->GetResultType();
2472  switch (type) {
2473    case Primitive::kPrimInt: {
2474      Register out_reg = out.AsRegister<Register>();
2475      Register first_reg = first.AsRegister<Register>();
2476      // Arm doesn't mask the shift count so we need to do it ourselves.
2477      if (second.IsRegister()) {
2478        Register second_reg = second.AsRegister<Register>();
2479        __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2480        if (op->IsShl()) {
2481          __ Lsl(out_reg, first_reg, second_reg);
2482        } else if (op->IsShr()) {
2483          __ Asr(out_reg, first_reg, second_reg);
2484        } else {
2485          __ Lsr(out_reg, first_reg, second_reg);
2486        }
2487      } else {
2488        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2489        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2490        if (shift_value == 0) {  // arm does not support shifting with 0 immediate.
2491          __ Mov(out_reg, first_reg);
2492        } else if (op->IsShl()) {
2493          __ Lsl(out_reg, first_reg, shift_value);
2494        } else if (op->IsShr()) {
2495          __ Asr(out_reg, first_reg, shift_value);
2496        } else {
2497          __ Lsr(out_reg, first_reg, shift_value);
2498        }
2499      }
2500      break;
2501    }
2502    case Primitive::kPrimLong: {
2503      Register o_h = out.AsRegisterPairHigh<Register>();
2504      Register o_l = out.AsRegisterPairLow<Register>();
2505
2506      Register temp = locations->GetTemp(0).AsRegister<Register>();
2507
2508      Register high = first.AsRegisterPairHigh<Register>();
2509      Register low = first.AsRegisterPairLow<Register>();
2510
2511      Register second_reg = second.AsRegister<Register>();
2512
2513      if (op->IsShl()) {
2514        // Shift the high part
2515        __ and_(second_reg, second_reg, ShifterOperand(63));
2516        __ Lsl(o_h, high, second_reg);
2517        // Shift the low part and `or` what overflew on the high part
2518        __ rsb(temp, second_reg, ShifterOperand(32));
2519        __ Lsr(temp, low, temp);
2520        __ orr(o_h, o_h, ShifterOperand(temp));
2521        // If the shift is > 32 bits, override the high part
2522        __ subs(temp, second_reg, ShifterOperand(32));
2523        __ it(PL);
2524        __ Lsl(o_h, low, temp, false, PL);
2525        // Shift the low part
2526        __ Lsl(o_l, low, second_reg);
2527      } else if (op->IsShr()) {
2528        // Shift the low part
2529        __ and_(second_reg, second_reg, ShifterOperand(63));
2530        __ Lsr(o_l, low, second_reg);
2531        // Shift the high part and `or` what underflew on the low part
2532        __ rsb(temp, second_reg, ShifterOperand(32));
2533        __ Lsl(temp, high, temp);
2534        __ orr(o_l, o_l, ShifterOperand(temp));
2535        // If the shift is > 32 bits, override the low part
2536        __ subs(temp, second_reg, ShifterOperand(32));
2537        __ it(PL);
2538        __ Asr(o_l, high, temp, false, PL);
2539        // Shift the high part
2540        __ Asr(o_h, high, second_reg);
2541      } else {
2542        // same as Shr except we use `Lsr`s and not `Asr`s
2543        __ and_(second_reg, second_reg, ShifterOperand(63));
2544        __ Lsr(o_l, low, second_reg);
2545        __ rsb(temp, second_reg, ShifterOperand(32));
2546        __ Lsl(temp, high, temp);
2547        __ orr(o_l, o_l, ShifterOperand(temp));
2548        __ subs(temp, second_reg, ShifterOperand(32));
2549        __ it(PL);
2550        __ Lsr(o_l, high, temp, false, PL);
2551        __ Lsr(o_h, high, second_reg);
2552      }
2553      break;
2554    }
2555    default:
2556      LOG(FATAL) << "Unexpected operation type " << type;
2557  }
2558}
2559
2560void LocationsBuilderARM::VisitShl(HShl* shl) {
2561  HandleShift(shl);
2562}
2563
2564void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2565  HandleShift(shl);
2566}
2567
2568void LocationsBuilderARM::VisitShr(HShr* shr) {
2569  HandleShift(shr);
2570}
2571
2572void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2573  HandleShift(shr);
2574}
2575
2576void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2577  HandleShift(ushr);
2578}
2579
2580void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2581  HandleShift(ushr);
2582}
2583
2584void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
2585  LocationSummary* locations =
2586      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2587  InvokeRuntimeCallingConvention calling_convention;
2588  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2589  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2590  locations->SetOut(Location::RegisterLocation(R0));
2591}
2592
2593void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2594  InvokeRuntimeCallingConvention calling_convention;
2595  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
2596  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
2597  codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2598                          instruction,
2599                          instruction->GetDexPc(),
2600                          nullptr);
2601}
2602
2603void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2604  LocationSummary* locations =
2605      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2606  InvokeRuntimeCallingConvention calling_convention;
2607  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2608  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2609  locations->SetOut(Location::RegisterLocation(R0));
2610  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2611}
2612
2613void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2614  InvokeRuntimeCallingConvention calling_convention;
2615  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
2616  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
2617  codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2618                          instruction,
2619                          instruction->GetDexPc(),
2620                          nullptr);
2621}
2622
2623void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
2624  LocationSummary* locations =
2625      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2626  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2627  if (location.IsStackSlot()) {
2628    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2629  } else if (location.IsDoubleStackSlot()) {
2630    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2631  }
2632  locations->SetOut(location);
2633}
2634
2635void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
2636  // Nothing to do, the parameter is already at its location.
2637  UNUSED(instruction);
2638}
2639
2640void LocationsBuilderARM::VisitNot(HNot* not_) {
2641  LocationSummary* locations =
2642      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
2643  locations->SetInAt(0, Location::RequiresRegister());
2644  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2645}
2646
2647void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2648  LocationSummary* locations = not_->GetLocations();
2649  Location out = locations->Out();
2650  Location in = locations->InAt(0);
2651  switch (not_->GetResultType()) {
2652    case Primitive::kPrimInt:
2653      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
2654      break;
2655
2656    case Primitive::kPrimLong:
2657      __ mvn(out.AsRegisterPairLow<Register>(),
2658             ShifterOperand(in.AsRegisterPairLow<Register>()));
2659      __ mvn(out.AsRegisterPairHigh<Register>(),
2660             ShifterOperand(in.AsRegisterPairHigh<Register>()));
2661      break;
2662
2663    default:
2664      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2665  }
2666}
2667
2668void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
2669  LocationSummary* locations =
2670      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
2671  locations->SetInAt(0, Location::RequiresRegister());
2672  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2673}
2674
2675void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
2676  LocationSummary* locations = bool_not->GetLocations();
2677  Location out = locations->Out();
2678  Location in = locations->InAt(0);
2679  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
2680}
2681
2682void LocationsBuilderARM::VisitCompare(HCompare* compare) {
2683  LocationSummary* locations =
2684      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
2685  switch (compare->InputAt(0)->GetType()) {
2686    case Primitive::kPrimLong: {
2687      locations->SetInAt(0, Location::RequiresRegister());
2688      locations->SetInAt(1, Location::RequiresRegister());
2689      // Output overlaps because it is written before doing the low comparison.
2690      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2691      break;
2692    }
2693    case Primitive::kPrimFloat:
2694    case Primitive::kPrimDouble: {
2695      locations->SetInAt(0, Location::RequiresFpuRegister());
2696      locations->SetInAt(1, Location::RequiresFpuRegister());
2697      locations->SetOut(Location::RequiresRegister());
2698      break;
2699    }
2700    default:
2701      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2702  }
2703}
2704
2705void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
2706  LocationSummary* locations = compare->GetLocations();
2707  Register out = locations->Out().AsRegister<Register>();
2708  Location left = locations->InAt(0);
2709  Location right = locations->InAt(1);
2710
2711  Label less, greater, done;
2712  Primitive::Type type = compare->InputAt(0)->GetType();
2713  switch (type) {
2714    case Primitive::kPrimLong: {
2715      __ cmp(left.AsRegisterPairHigh<Register>(),
2716             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
2717      __ b(&less, LT);
2718      __ b(&greater, GT);
2719      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2720      __ LoadImmediate(out, 0);
2721      __ cmp(left.AsRegisterPairLow<Register>(),
2722             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
2723      break;
2724    }
2725    case Primitive::kPrimFloat:
2726    case Primitive::kPrimDouble: {
2727      __ LoadImmediate(out, 0);
2728      if (type == Primitive::kPrimFloat) {
2729        __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
2730      } else {
2731        __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2732                 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2733      }
2734      __ vmstat();  // transfer FP status register to ARM APSR.
2735      __ b(compare->IsGtBias() ? &greater : &less, VS);  // VS for unordered.
2736      break;
2737    }
2738    default:
2739      LOG(FATAL) << "Unexpected compare type " << type;
2740  }
2741  __ b(&done, EQ);
2742  __ b(&less, CC);  // CC is for both: unsigned compare for longs and 'less than' for floats.
2743
2744  __ Bind(&greater);
2745  __ LoadImmediate(out, 1);
2746  __ b(&done);
2747
2748  __ Bind(&less);
2749  __ LoadImmediate(out, -1);
2750
2751  __ Bind(&done);
2752}
2753
2754void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
2755  LocationSummary* locations =
2756      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2757  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2758    locations->SetInAt(i, Location::Any());
2759  }
2760  locations->SetOut(Location::Any());
2761}
2762
2763void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
2764  UNUSED(instruction);
2765  LOG(FATAL) << "Unreachable";
2766}
2767
2768void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2769  // TODO (ported from quick): revisit Arm barrier kinds
2770  DmbOptions flavour = DmbOptions::ISH;  // quiet c++ warnings
2771  switch (kind) {
2772    case MemBarrierKind::kAnyStore:
2773    case MemBarrierKind::kLoadAny:
2774    case MemBarrierKind::kAnyAny: {
2775      flavour = DmbOptions::ISH;
2776      break;
2777    }
2778    case MemBarrierKind::kStoreStore: {
2779      flavour = DmbOptions::ISHST;
2780      break;
2781    }
2782    default:
2783      LOG(FATAL) << "Unexpected memory barrier " << kind;
2784  }
2785  __ dmb(flavour);
2786}
2787
2788void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2789                                                         uint32_t offset,
2790                                                         Register out_lo,
2791                                                         Register out_hi) {
2792  if (offset != 0) {
2793    __ LoadImmediate(out_lo, offset);
2794    __ add(IP, addr, ShifterOperand(out_lo));
2795    addr = IP;
2796  }
2797  __ ldrexd(out_lo, out_hi, addr);
2798}
2799
2800void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2801                                                          uint32_t offset,
2802                                                          Register value_lo,
2803                                                          Register value_hi,
2804                                                          Register temp1,
2805                                                          Register temp2,
2806                                                          HInstruction* instruction) {
2807  Label fail;
2808  if (offset != 0) {
2809    __ LoadImmediate(temp1, offset);
2810    __ add(IP, addr, ShifterOperand(temp1));
2811    addr = IP;
2812  }
2813  __ Bind(&fail);
2814  // We need a load followed by store. (The address used in a STREX instruction must
2815  // be the same as the address in the most recently executed LDREX instruction.)
2816  __ ldrexd(temp1, temp2, addr);
2817  codegen_->MaybeRecordImplicitNullCheck(instruction);
2818  __ strexd(temp1, value_lo, value_hi, addr);
2819  __ cmp(temp1, ShifterOperand(0));
2820  __ b(&fail, NE);
2821}
2822
2823void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2824  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2825
2826  LocationSummary* locations =
2827      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2828  locations->SetInAt(0, Location::RequiresRegister());
2829
2830  Primitive::Type field_type = field_info.GetFieldType();
2831  if (Primitive::IsFloatingPointType(field_type)) {
2832    locations->SetInAt(1, Location::RequiresFpuRegister());
2833  } else {
2834    locations->SetInAt(1, Location::RequiresRegister());
2835  }
2836
2837  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
2838  bool generate_volatile = field_info.IsVolatile()
2839      && is_wide
2840      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
2841  // Temporary registers for the write barrier.
2842  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2843  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2844    locations->AddTemp(Location::RequiresRegister());
2845    locations->AddTemp(Location::RequiresRegister());
2846  } else if (generate_volatile) {
2847    // Arm encoding have some additional constraints for ldrexd/strexd:
2848    // - registers need to be consecutive
2849    // - the first register should be even but not R14.
2850    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2851    // enable Arm encoding.
2852    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2853
2854    locations->AddTemp(Location::RequiresRegister());
2855    locations->AddTemp(Location::RequiresRegister());
2856    if (field_type == Primitive::kPrimDouble) {
2857      // For doubles we need two more registers to copy the value.
2858      locations->AddTemp(Location::RegisterLocation(R2));
2859      locations->AddTemp(Location::RegisterLocation(R3));
2860    }
2861  }
2862}
2863
2864void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
2865                                                 const FieldInfo& field_info) {
2866  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2867
2868  LocationSummary* locations = instruction->GetLocations();
2869  Register base = locations->InAt(0).AsRegister<Register>();
2870  Location value = locations->InAt(1);
2871
2872  bool is_volatile = field_info.IsVolatile();
2873  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
2874  Primitive::Type field_type = field_info.GetFieldType();
2875  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2876
2877  if (is_volatile) {
2878    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2879  }
2880
2881  switch (field_type) {
2882    case Primitive::kPrimBoolean:
2883    case Primitive::kPrimByte: {
2884      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
2885      break;
2886    }
2887
2888    case Primitive::kPrimShort:
2889    case Primitive::kPrimChar: {
2890      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
2891      break;
2892    }
2893
2894    case Primitive::kPrimInt:
2895    case Primitive::kPrimNot: {
2896      __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
2897      break;
2898    }
2899
2900    case Primitive::kPrimLong: {
2901      if (is_volatile && !atomic_ldrd_strd) {
2902        GenerateWideAtomicStore(base, offset,
2903                                value.AsRegisterPairLow<Register>(),
2904                                value.AsRegisterPairHigh<Register>(),
2905                                locations->GetTemp(0).AsRegister<Register>(),
2906                                locations->GetTemp(1).AsRegister<Register>(),
2907                                instruction);
2908      } else {
2909        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
2910        codegen_->MaybeRecordImplicitNullCheck(instruction);
2911      }
2912      break;
2913    }
2914
2915    case Primitive::kPrimFloat: {
2916      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
2917      break;
2918    }
2919
2920    case Primitive::kPrimDouble: {
2921      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
2922      if (is_volatile && !atomic_ldrd_strd) {
2923        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
2924        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
2925
2926        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
2927
2928        GenerateWideAtomicStore(base, offset,
2929                                value_reg_lo,
2930                                value_reg_hi,
2931                                locations->GetTemp(2).AsRegister<Register>(),
2932                                locations->GetTemp(3).AsRegister<Register>(),
2933                                instruction);
2934      } else {
2935        __ StoreDToOffset(value_reg, base, offset);
2936        codegen_->MaybeRecordImplicitNullCheck(instruction);
2937      }
2938      break;
2939    }
2940
2941    case Primitive::kPrimVoid:
2942      LOG(FATAL) << "Unreachable type " << field_type;
2943      UNREACHABLE();
2944  }
2945
2946  // Longs and doubles are handled in the switch.
2947  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
2948    codegen_->MaybeRecordImplicitNullCheck(instruction);
2949  }
2950
2951  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2952    Register temp = locations->GetTemp(0).AsRegister<Register>();
2953    Register card = locations->GetTemp(1).AsRegister<Register>();
2954    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2955  }
2956
2957  if (is_volatile) {
2958    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2959  }
2960}
2961
2962void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2963  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2964  LocationSummary* locations =
2965      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2966  locations->SetInAt(0, Location::RequiresRegister());
2967
2968  bool volatile_for_double = field_info.IsVolatile()
2969      && (field_info.GetFieldType() == Primitive::kPrimDouble)
2970      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
2971  bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
2972
2973  if (Primitive::IsFloatingPointType(instruction->GetType())) {
2974    locations->SetOut(Location::RequiresFpuRegister());
2975  } else {
2976    locations->SetOut(Location::RequiresRegister(),
2977                      (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
2978  }
2979  if (volatile_for_double) {
2980    // Arm encoding have some additional constraints for ldrexd/strexd:
2981    // - registers need to be consecutive
2982    // - the first register should be even but not R14.
2983    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2984    // enable Arm encoding.
2985    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2986    locations->AddTemp(Location::RequiresRegister());
2987    locations->AddTemp(Location::RequiresRegister());
2988  }
2989}
2990
2991void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
2992                                                 const FieldInfo& field_info) {
2993  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
2994
2995  LocationSummary* locations = instruction->GetLocations();
2996  Register base = locations->InAt(0).AsRegister<Register>();
2997  Location out = locations->Out();
2998  bool is_volatile = field_info.IsVolatile();
2999  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
3000  Primitive::Type field_type = field_info.GetFieldType();
3001  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3002
3003  switch (field_type) {
3004    case Primitive::kPrimBoolean: {
3005      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
3006      break;
3007    }
3008
3009    case Primitive::kPrimByte: {
3010      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
3011      break;
3012    }
3013
3014    case Primitive::kPrimShort: {
3015      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
3016      break;
3017    }
3018
3019    case Primitive::kPrimChar: {
3020      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
3021      break;
3022    }
3023
3024    case Primitive::kPrimInt:
3025    case Primitive::kPrimNot: {
3026      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
3027      break;
3028    }
3029
3030    case Primitive::kPrimLong: {
3031      if (is_volatile && !atomic_ldrd_strd) {
3032        GenerateWideAtomicLoad(base, offset,
3033                               out.AsRegisterPairLow<Register>(),
3034                               out.AsRegisterPairHigh<Register>());
3035      } else {
3036        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3037      }
3038      break;
3039    }
3040
3041    case Primitive::kPrimFloat: {
3042      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
3043      break;
3044    }
3045
3046    case Primitive::kPrimDouble: {
3047      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
3048      if (is_volatile && !atomic_ldrd_strd) {
3049        Register lo = locations->GetTemp(0).AsRegister<Register>();
3050        Register hi = locations->GetTemp(1).AsRegister<Register>();
3051        GenerateWideAtomicLoad(base, offset, lo, hi);
3052        codegen_->MaybeRecordImplicitNullCheck(instruction);
3053        __ vmovdrr(out_reg, lo, hi);
3054      } else {
3055        __ LoadDFromOffset(out_reg, base, offset);
3056        codegen_->MaybeRecordImplicitNullCheck(instruction);
3057      }
3058      break;
3059    }
3060
3061    case Primitive::kPrimVoid:
3062      LOG(FATAL) << "Unreachable type " << field_type;
3063      UNREACHABLE();
3064  }
3065
3066  // Doubles are handled in the switch.
3067  if (field_type != Primitive::kPrimDouble) {
3068    codegen_->MaybeRecordImplicitNullCheck(instruction);
3069  }
3070
3071  if (is_volatile) {
3072    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3073  }
3074}
3075
3076void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3077  HandleFieldSet(instruction, instruction->GetFieldInfo());
3078}
3079
3080void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3081  HandleFieldSet(instruction, instruction->GetFieldInfo());
3082}
3083
3084void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3085  HandleFieldGet(instruction, instruction->GetFieldInfo());
3086}
3087
3088void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3089  HandleFieldGet(instruction, instruction->GetFieldInfo());
3090}
3091
3092void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3093  HandleFieldGet(instruction, instruction->GetFieldInfo());
3094}
3095
3096void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3097  HandleFieldGet(instruction, instruction->GetFieldInfo());
3098}
3099
3100void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3101  HandleFieldSet(instruction, instruction->GetFieldInfo());
3102}
3103
3104void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3105  HandleFieldSet(instruction, instruction->GetFieldInfo());
3106}
3107
3108void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
3109  LocationSummary* locations =
3110      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3111  locations->SetInAt(0, Location::RequiresRegister());
3112  if (instruction->HasUses()) {
3113    locations->SetOut(Location::SameAsFirstInput());
3114  }
3115}
3116
3117void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
3118  if (codegen_->CanMoveNullCheckToUser(instruction)) {
3119    return;
3120  }
3121  Location obj = instruction->GetLocations()->InAt(0);
3122
3123  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3124  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3125}
3126
3127void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
3128  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
3129  codegen_->AddSlowPath(slow_path);
3130
3131  LocationSummary* locations = instruction->GetLocations();
3132  Location obj = locations->InAt(0);
3133
3134  __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
3135  __ b(slow_path->GetEntryLabel(), EQ);
3136}
3137
3138void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3139  if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3140    GenerateImplicitNullCheck(instruction);
3141  } else {
3142    GenerateExplicitNullCheck(instruction);
3143  }
3144}
3145
3146void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
3147  LocationSummary* locations =
3148      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3149  locations->SetInAt(0, Location::RequiresRegister());
3150  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3151  if (Primitive::IsFloatingPointType(instruction->GetType())) {
3152    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3153  } else {
3154    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3155  }
3156}
3157
3158void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3159  LocationSummary* locations = instruction->GetLocations();
3160  Register obj = locations->InAt(0).AsRegister<Register>();
3161  Location index = locations->InAt(1);
3162
3163  switch (instruction->GetType()) {
3164    case Primitive::kPrimBoolean: {
3165      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
3166      Register out = locations->Out().AsRegister<Register>();
3167      if (index.IsConstant()) {
3168        size_t offset =
3169            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
3170        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3171      } else {
3172        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
3173        __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3174      }
3175      break;
3176    }
3177
3178    case Primitive::kPrimByte: {
3179      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
3180      Register out = locations->Out().AsRegister<Register>();
3181      if (index.IsConstant()) {
3182        size_t offset =
3183            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
3184        __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3185      } else {
3186        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
3187        __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3188      }
3189      break;
3190    }
3191
3192    case Primitive::kPrimShort: {
3193      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
3194      Register out = locations->Out().AsRegister<Register>();
3195      if (index.IsConstant()) {
3196        size_t offset =
3197            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
3198        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3199      } else {
3200        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
3201        __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3202      }
3203      break;
3204    }
3205
3206    case Primitive::kPrimChar: {
3207      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
3208      Register out = locations->Out().AsRegister<Register>();
3209      if (index.IsConstant()) {
3210        size_t offset =
3211            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
3212        __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3213      } else {
3214        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
3215        __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3216      }
3217      break;
3218    }
3219
3220    case Primitive::kPrimInt:
3221    case Primitive::kPrimNot: {
3222      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3223      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3224      Register out = locations->Out().AsRegister<Register>();
3225      if (index.IsConstant()) {
3226        size_t offset =
3227            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3228        __ LoadFromOffset(kLoadWord, out, obj, offset);
3229      } else {
3230        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3231        __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3232      }
3233      break;
3234    }
3235
3236    case Primitive::kPrimLong: {
3237      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
3238      Location out = locations->Out();
3239      if (index.IsConstant()) {
3240        size_t offset =
3241            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3242        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
3243      } else {
3244        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3245        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
3246      }
3247      break;
3248    }
3249
3250    case Primitive::kPrimFloat: {
3251      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3252      Location out = locations->Out();
3253      DCHECK(out.IsFpuRegister());
3254      if (index.IsConstant()) {
3255        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3256        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3257      } else {
3258        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3259        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3260      }
3261      break;
3262    }
3263
3264    case Primitive::kPrimDouble: {
3265      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3266      Location out = locations->Out();
3267      DCHECK(out.IsFpuRegisterPair());
3268      if (index.IsConstant()) {
3269        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3270        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3271      } else {
3272        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3273        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3274      }
3275      break;
3276    }
3277
3278    case Primitive::kPrimVoid:
3279      LOG(FATAL) << "Unreachable type " << instruction->GetType();
3280      UNREACHABLE();
3281  }
3282  codegen_->MaybeRecordImplicitNullCheck(instruction);
3283}
3284
3285void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
3286  Primitive::Type value_type = instruction->GetComponentType();
3287
3288  bool needs_write_barrier =
3289      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3290  bool needs_runtime_call = instruction->NeedsTypeCheck();
3291
3292  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3293      instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3294  if (needs_runtime_call) {
3295    InvokeRuntimeCallingConvention calling_convention;
3296    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3297    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3298    locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3299  } else {
3300    locations->SetInAt(0, Location::RequiresRegister());
3301    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3302    if (Primitive::IsFloatingPointType(value_type)) {
3303      locations->SetInAt(2, Location::RequiresFpuRegister());
3304    } else {
3305      locations->SetInAt(2, Location::RequiresRegister());
3306    }
3307
3308    if (needs_write_barrier) {
3309      // Temporary registers for the write barrier.
3310      locations->AddTemp(Location::RequiresRegister());
3311      locations->AddTemp(Location::RequiresRegister());
3312    }
3313  }
3314}
3315
3316void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3317  LocationSummary* locations = instruction->GetLocations();
3318  Register obj = locations->InAt(0).AsRegister<Register>();
3319  Location index = locations->InAt(1);
3320  Primitive::Type value_type = instruction->GetComponentType();
3321  bool needs_runtime_call = locations->WillCall();
3322  bool needs_write_barrier =
3323      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3324
3325  switch (value_type) {
3326    case Primitive::kPrimBoolean:
3327    case Primitive::kPrimByte: {
3328      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
3329      Register value = locations->InAt(2).AsRegister<Register>();
3330      if (index.IsConstant()) {
3331        size_t offset =
3332            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
3333        __ StoreToOffset(kStoreByte, value, obj, offset);
3334      } else {
3335        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
3336        __ StoreToOffset(kStoreByte, value, IP, data_offset);
3337      }
3338      break;
3339    }
3340
3341    case Primitive::kPrimShort:
3342    case Primitive::kPrimChar: {
3343      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
3344      Register value = locations->InAt(2).AsRegister<Register>();
3345      if (index.IsConstant()) {
3346        size_t offset =
3347            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
3348        __ StoreToOffset(kStoreHalfword, value, obj, offset);
3349      } else {
3350        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
3351        __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3352      }
3353      break;
3354    }
3355
3356    case Primitive::kPrimInt:
3357    case Primitive::kPrimNot: {
3358      if (!needs_runtime_call) {
3359        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3360        Register value = locations->InAt(2).AsRegister<Register>();
3361        if (index.IsConstant()) {
3362          size_t offset =
3363              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3364          __ StoreToOffset(kStoreWord, value, obj, offset);
3365        } else {
3366          DCHECK(index.IsRegister()) << index;
3367          __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3368          __ StoreToOffset(kStoreWord, value, IP, data_offset);
3369        }
3370        codegen_->MaybeRecordImplicitNullCheck(instruction);
3371        if (needs_write_barrier) {
3372          DCHECK_EQ(value_type, Primitive::kPrimNot);
3373          Register temp = locations->GetTemp(0).AsRegister<Register>();
3374          Register card = locations->GetTemp(1).AsRegister<Register>();
3375          codegen_->MarkGCCard(temp, card, obj, value);
3376        }
3377      } else {
3378        DCHECK_EQ(value_type, Primitive::kPrimNot);
3379        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3380                                instruction,
3381                                instruction->GetDexPc(),
3382                                nullptr);
3383      }
3384      break;
3385    }
3386
3387    case Primitive::kPrimLong: {
3388      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
3389      Location value = locations->InAt(2);
3390      if (index.IsConstant()) {
3391        size_t offset =
3392            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3393        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
3394      } else {
3395        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3396        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
3397      }
3398      break;
3399    }
3400
3401    case Primitive::kPrimFloat: {
3402      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3403      Location value = locations->InAt(2);
3404      DCHECK(value.IsFpuRegister());
3405      if (index.IsConstant()) {
3406        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3407        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3408      } else {
3409        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3410        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3411      }
3412      break;
3413    }
3414
3415    case Primitive::kPrimDouble: {
3416      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3417      Location value = locations->InAt(2);
3418      DCHECK(value.IsFpuRegisterPair());
3419      if (index.IsConstant()) {
3420        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3421        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3422      } else {
3423        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3424        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3425      }
3426
3427      break;
3428    }
3429
3430    case Primitive::kPrimVoid:
3431      LOG(FATAL) << "Unreachable type " << value_type;
3432      UNREACHABLE();
3433  }
3434
3435  // Ints and objects are handled in the switch.
3436  if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3437    codegen_->MaybeRecordImplicitNullCheck(instruction);
3438  }
3439}
3440
3441void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
3442  LocationSummary* locations =
3443      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3444  locations->SetInAt(0, Location::RequiresRegister());
3445  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3446}
3447
3448void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3449  LocationSummary* locations = instruction->GetLocations();
3450  uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
3451  Register obj = locations->InAt(0).AsRegister<Register>();
3452  Register out = locations->Out().AsRegister<Register>();
3453  __ LoadFromOffset(kLoadWord, out, obj, offset);
3454  codegen_->MaybeRecordImplicitNullCheck(instruction);
3455}
3456
3457void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3458  LocationSummary* locations =
3459      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3460  locations->SetInAt(0, Location::RequiresRegister());
3461  locations->SetInAt(1, Location::RequiresRegister());
3462  if (instruction->HasUses()) {
3463    locations->SetOut(Location::SameAsFirstInput());
3464  }
3465}
3466
3467void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3468  LocationSummary* locations = instruction->GetLocations();
3469  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
3470      instruction, locations->InAt(0), locations->InAt(1));
3471  codegen_->AddSlowPath(slow_path);
3472
3473  Register index = locations->InAt(0).AsRegister<Register>();
3474  Register length = locations->InAt(1).AsRegister<Register>();
3475
3476  __ cmp(index, ShifterOperand(length));
3477  __ b(slow_path->GetEntryLabel(), CS);
3478}
3479
3480void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
3481  Label is_null;
3482  __ CompareAndBranchIfZero(value, &is_null);
3483  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3484  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3485  __ strb(card, Address(card, temp));
3486  __ Bind(&is_null);
3487}
3488
3489void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3490  temp->SetLocations(nullptr);
3491}
3492
3493void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3494  // Nothing to do, this is driven by the code generator.
3495  UNUSED(temp);
3496}
3497
3498void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
3499  UNUSED(instruction);
3500  LOG(FATAL) << "Unreachable";
3501}
3502
3503void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
3504  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3505}
3506
3507void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3508  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3509}
3510
3511void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3512  HBasicBlock* block = instruction->GetBlock();
3513  if (block->GetLoopInformation() != nullptr) {
3514    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3515    // The back edge will generate the suspend check.
3516    return;
3517  }
3518  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3519    // The goto will generate the suspend check.
3520    return;
3521  }
3522  GenerateSuspendCheck(instruction, nullptr);
3523}
3524
3525void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3526                                                       HBasicBlock* successor) {
3527  SuspendCheckSlowPathARM* slow_path =
3528      new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
3529  codegen_->AddSlowPath(slow_path);
3530
3531  __ LoadFromOffset(
3532      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3533  __ cmp(IP, ShifterOperand(0));
3534  // TODO: Figure out the branch offsets and use cbz/cbnz.
3535  if (successor == nullptr) {
3536    __ b(slow_path->GetEntryLabel(), NE);
3537    __ Bind(slow_path->GetReturnLabel());
3538  } else {
3539    __ b(codegen_->GetLabelOf(successor), EQ);
3540    __ b(slow_path->GetEntryLabel());
3541  }
3542}
3543
3544ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3545  return codegen_->GetAssembler();
3546}
3547
3548void ParallelMoveResolverARM::EmitMove(size_t index) {
3549  MoveOperands* move = moves_.Get(index);
3550  Location source = move->GetSource();
3551  Location destination = move->GetDestination();
3552
3553  if (source.IsRegister()) {
3554    if (destination.IsRegister()) {
3555      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
3556    } else {
3557      DCHECK(destination.IsStackSlot());
3558      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
3559                       SP, destination.GetStackIndex());
3560    }
3561  } else if (source.IsStackSlot()) {
3562    if (destination.IsRegister()) {
3563      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
3564                        SP, source.GetStackIndex());
3565    } else if (destination.IsFpuRegister()) {
3566      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
3567    } else {
3568      DCHECK(destination.IsStackSlot());
3569      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3570      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3571    }
3572  } else if (source.IsFpuRegister()) {
3573    if (destination.IsFpuRegister()) {
3574      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
3575    } else {
3576      DCHECK(destination.IsStackSlot());
3577      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3578    }
3579  } else if (source.IsDoubleStackSlot()) {
3580    if (destination.IsDoubleStackSlot()) {
3581      __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
3582      __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
3583    } else if (destination.IsRegisterPair()) {
3584      DCHECK(ExpectedPairLayout(destination));
3585      __ LoadFromOffset(
3586          kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
3587    } else {
3588      DCHECK(destination.IsFpuRegisterPair()) << destination;
3589      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3590                         SP,
3591                         source.GetStackIndex());
3592    }
3593  } else if (source.IsRegisterPair()) {
3594    if (destination.IsRegisterPair()) {
3595      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
3596      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
3597    } else {
3598      DCHECK(destination.IsDoubleStackSlot()) << destination;
3599      DCHECK(ExpectedPairLayout(source));
3600      __ StoreToOffset(
3601          kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
3602    }
3603  } else if (source.IsFpuRegisterPair()) {
3604    if (destination.IsFpuRegisterPair()) {
3605      __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3606               FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
3607    } else {
3608      DCHECK(destination.IsDoubleStackSlot()) << destination;
3609      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
3610                        SP,
3611                        destination.GetStackIndex());
3612    }
3613  } else {
3614    DCHECK(source.IsConstant()) << source;
3615    HConstant* constant = source.GetConstant();
3616    if (constant->IsIntConstant() || constant->IsNullConstant()) {
3617      int32_t value = CodeGenerator::GetInt32ValueOf(constant);
3618      if (destination.IsRegister()) {
3619        __ LoadImmediate(destination.AsRegister<Register>(), value);
3620      } else {
3621        DCHECK(destination.IsStackSlot());
3622        __ LoadImmediate(IP, value);
3623        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3624      }
3625    } else if (constant->IsLongConstant()) {
3626      int64_t value = constant->AsLongConstant()->GetValue();
3627      if (destination.IsRegisterPair()) {
3628        __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
3629        __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
3630      } else {
3631        DCHECK(destination.IsDoubleStackSlot()) << destination;
3632        __ LoadImmediate(IP, Low32Bits(value));
3633        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3634        __ LoadImmediate(IP, High32Bits(value));
3635        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3636      }
3637    } else if (constant->IsDoubleConstant()) {
3638      double value = constant->AsDoubleConstant()->GetValue();
3639      if (destination.IsFpuRegisterPair()) {
3640        __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
3641      } else {
3642        DCHECK(destination.IsDoubleStackSlot()) << destination;
3643        uint64_t int_value = bit_cast<uint64_t, double>(value);
3644        __ LoadImmediate(IP, Low32Bits(int_value));
3645        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3646        __ LoadImmediate(IP, High32Bits(int_value));
3647        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3648      }
3649    } else {
3650      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
3651      float value = constant->AsFloatConstant()->GetValue();
3652      if (destination.IsFpuRegister()) {
3653        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3654      } else {
3655        DCHECK(destination.IsStackSlot());
3656        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3657        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3658      }
3659    }
3660  }
3661}
3662
3663void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3664  __ Mov(IP, reg);
3665  __ LoadFromOffset(kLoadWord, reg, SP, mem);
3666  __ StoreToOffset(kStoreWord, IP, SP, mem);
3667}
3668
3669void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3670  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3671  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3672  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3673                    SP, mem1 + stack_offset);
3674  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3675  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3676                   SP, mem2 + stack_offset);
3677  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3678}
3679
3680void ParallelMoveResolverARM::EmitSwap(size_t index) {
3681  MoveOperands* move = moves_.Get(index);
3682  Location source = move->GetSource();
3683  Location destination = move->GetDestination();
3684
3685  if (source.IsRegister() && destination.IsRegister()) {
3686    DCHECK_NE(source.AsRegister<Register>(), IP);
3687    DCHECK_NE(destination.AsRegister<Register>(), IP);
3688    __ Mov(IP, source.AsRegister<Register>());
3689    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3690    __ Mov(destination.AsRegister<Register>(), IP);
3691  } else if (source.IsRegister() && destination.IsStackSlot()) {
3692    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
3693  } else if (source.IsStackSlot() && destination.IsRegister()) {
3694    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
3695  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3696    Exchange(source.GetStackIndex(), destination.GetStackIndex());
3697  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3698    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
3699    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
3700    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
3701  } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
3702    __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
3703    __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
3704    __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
3705    __ vmovrrd(destination.AsRegisterPairLow<Register>(),
3706               destination.AsRegisterPairHigh<Register>(),
3707               DTMP);
3708  } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
3709    Register low_reg = source.IsRegisterPair()
3710        ? source.AsRegisterPairLow<Register>()
3711        : destination.AsRegisterPairLow<Register>();
3712    int mem = source.IsRegisterPair()
3713        ? destination.GetStackIndex()
3714        : source.GetStackIndex();
3715    DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
3716    __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
3717    __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
3718    __ StoreDToOffset(DTMP, SP, mem);
3719  } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
3720    DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
3721    DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3722    __ vmovd(DTMP, first);
3723    __ vmovd(first, second);
3724    __ vmovd(second, DTMP);
3725  } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
3726    DRegister reg = source.IsFpuRegisterPair()
3727        ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
3728        : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3729    int mem = source.IsFpuRegisterPair()
3730        ? destination.GetStackIndex()
3731        : source.GetStackIndex();
3732    __ vmovd(DTMP, reg);
3733    __ LoadDFromOffset(reg, SP, mem);
3734    __ StoreDToOffset(DTMP, SP, mem);
3735  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3736    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3737                                           : destination.AsFpuRegister<SRegister>();
3738    int mem = source.IsFpuRegister()
3739        ? destination.GetStackIndex()
3740        : source.GetStackIndex();
3741
3742    __ vmovrs(IP, reg);
3743    __ LoadSFromOffset(reg, SP, mem);
3744    __ StoreToOffset(kStoreWord, IP, SP, mem);
3745  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
3746    Exchange(source.GetStackIndex(), destination.GetStackIndex());
3747    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
3748  } else {
3749    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
3750  }
3751}
3752
3753void ParallelMoveResolverARM::SpillScratch(int reg) {
3754  __ Push(static_cast<Register>(reg));
3755}
3756
3757void ParallelMoveResolverARM::RestoreScratch(int reg) {
3758  __ Pop(static_cast<Register>(reg));
3759}
3760
3761void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
3762  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3763      ? LocationSummary::kCallOnSlowPath
3764      : LocationSummary::kNoCall;
3765  LocationSummary* locations =
3766      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
3767  locations->SetOut(Location::RequiresRegister());
3768}
3769
3770void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
3771  Register out = cls->GetLocations()->Out().AsRegister<Register>();
3772  if (cls->IsReferrersClass()) {
3773    DCHECK(!cls->CanCallRuntime());
3774    DCHECK(!cls->MustGenerateClinitCheck());
3775    codegen_->LoadCurrentMethod(out);
3776    __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3777  } else {
3778    DCHECK(cls->CanCallRuntime());
3779    codegen_->LoadCurrentMethod(out);
3780    __ LoadFromOffset(
3781        kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
3782    __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
3783
3784    SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3785        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3786    codegen_->AddSlowPath(slow_path);
3787    __ cmp(out, ShifterOperand(0));
3788    __ b(slow_path->GetEntryLabel(), EQ);
3789    if (cls->MustGenerateClinitCheck()) {
3790      GenerateClassInitializationCheck(slow_path, out);
3791    } else {
3792      __ Bind(slow_path->GetExitLabel());
3793    }
3794  }
3795}
3796
3797void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3798  LocationSummary* locations =
3799      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3800  locations->SetInAt(0, Location::RequiresRegister());
3801  if (check->HasUses()) {
3802    locations->SetOut(Location::SameAsFirstInput());
3803  }
3804}
3805
3806void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
3807  // We assume the class is not null.
3808  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3809      check->GetLoadClass(), check, check->GetDexPc(), true);
3810  codegen_->AddSlowPath(slow_path);
3811  GenerateClassInitializationCheck(slow_path,
3812                                   check->GetLocations()->InAt(0).AsRegister<Register>());
3813}
3814
3815void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3816    SlowPathCodeARM* slow_path, Register class_reg) {
3817  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3818  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3819  __ b(slow_path->GetEntryLabel(), LT);
3820  // Even if the initialized flag is set, we may be in a situation where caches are not synced
3821  // properly. Therefore, we do a memory fence.
3822  __ dmb(ISH);
3823  __ Bind(slow_path->GetExitLabel());
3824}
3825
3826void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3827  LocationSummary* locations =
3828      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3829  locations->SetOut(Location::RequiresRegister());
3830}
3831
3832void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
3833  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
3834  codegen_->AddSlowPath(slow_path);
3835
3836  Register out = load->GetLocations()->Out().AsRegister<Register>();
3837  codegen_->LoadCurrentMethod(out);
3838  __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3839  __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
3840  __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
3841  __ cmp(out, ShifterOperand(0));
3842  __ b(slow_path->GetEntryLabel(), EQ);
3843  __ Bind(slow_path->GetExitLabel());
3844}
3845
3846void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
3847  LocationSummary* locations =
3848      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3849  locations->SetOut(Location::RequiresRegister());
3850}
3851
3852void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
3853  Register out = load->GetLocations()->Out().AsRegister<Register>();
3854  int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
3855  __ LoadFromOffset(kLoadWord, out, TR, offset);
3856  __ LoadImmediate(IP, 0);
3857  __ StoreToOffset(kStoreWord, IP, TR, offset);
3858}
3859
3860void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
3861  LocationSummary* locations =
3862      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3863  InvokeRuntimeCallingConvention calling_convention;
3864  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3865}
3866
3867void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
3868  codegen_->InvokeRuntime(
3869      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
3870}
3871
3872void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
3873  LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3874      ? LocationSummary::kNoCall
3875      : LocationSummary::kCallOnSlowPath;
3876  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3877  locations->SetInAt(0, Location::RequiresRegister());
3878  locations->SetInAt(1, Location::RequiresRegister());
3879  // The out register is used as a temporary, so it overlaps with the inputs.
3880  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3881}
3882
3883void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
3884  LocationSummary* locations = instruction->GetLocations();
3885  Register obj = locations->InAt(0).AsRegister<Register>();
3886  Register cls = locations->InAt(1).AsRegister<Register>();
3887  Register out = locations->Out().AsRegister<Register>();
3888  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3889  Label done, zero;
3890  SlowPathCodeARM* slow_path = nullptr;
3891
3892  // Return 0 if `obj` is null.
3893  // TODO: avoid this check if we know obj is not null.
3894  __ cmp(obj, ShifterOperand(0));
3895  __ b(&zero, EQ);
3896  // Compare the class of `obj` with `cls`.
3897  __ LoadFromOffset(kLoadWord, out, obj, class_offset);
3898  __ cmp(out, ShifterOperand(cls));
3899  if (instruction->IsClassFinal()) {
3900    // Classes must be equal for the instanceof to succeed.
3901    __ b(&zero, NE);
3902    __ LoadImmediate(out, 1);
3903    __ b(&done);
3904  } else {
3905    // If the classes are not equal, we go into a slow path.
3906    DCHECK(locations->OnlyCallsOnSlowPath());
3907    slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3908        instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
3909    codegen_->AddSlowPath(slow_path);
3910    __ b(slow_path->GetEntryLabel(), NE);
3911    __ LoadImmediate(out, 1);
3912    __ b(&done);
3913  }
3914  __ Bind(&zero);
3915  __ LoadImmediate(out, 0);
3916  if (slow_path != nullptr) {
3917    __ Bind(slow_path->GetExitLabel());
3918  }
3919  __ Bind(&done);
3920}
3921
3922void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
3923  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3924      instruction, LocationSummary::kCallOnSlowPath);
3925  locations->SetInAt(0, Location::RequiresRegister());
3926  locations->SetInAt(1, Location::RequiresRegister());
3927  locations->AddTemp(Location::RequiresRegister());
3928}
3929
3930void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
3931  LocationSummary* locations = instruction->GetLocations();
3932  Register obj = locations->InAt(0).AsRegister<Register>();
3933  Register cls = locations->InAt(1).AsRegister<Register>();
3934  Register temp = locations->GetTemp(0).AsRegister<Register>();
3935  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3936
3937  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3938      instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3939  codegen_->AddSlowPath(slow_path);
3940
3941  // TODO: avoid this check if we know obj is not null.
3942  __ cmp(obj, ShifterOperand(0));
3943  __ b(slow_path->GetExitLabel(), EQ);
3944  // Compare the class of `obj` with `cls`.
3945  __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
3946  __ cmp(temp, ShifterOperand(cls));
3947  __ b(slow_path->GetEntryLabel(), NE);
3948  __ Bind(slow_path->GetExitLabel());
3949}
3950
3951void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3952  LocationSummary* locations =
3953      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3954  InvokeRuntimeCallingConvention calling_convention;
3955  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3956}
3957
3958void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3959  codegen_->InvokeRuntime(instruction->IsEnter()
3960        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
3961      instruction,
3962      instruction->GetDexPc(),
3963      nullptr);
3964}
3965
3966void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3967void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3968void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3969
3970void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3971  LocationSummary* locations =
3972      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3973  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3974         || instruction->GetResultType() == Primitive::kPrimLong);
3975  locations->SetInAt(0, Location::RequiresRegister());
3976  locations->SetInAt(1, Location::RequiresRegister());
3977  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3978}
3979
3980void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
3981  HandleBitwiseOperation(instruction);
3982}
3983
3984void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
3985  HandleBitwiseOperation(instruction);
3986}
3987
3988void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
3989  HandleBitwiseOperation(instruction);
3990}
3991
3992void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3993  LocationSummary* locations = instruction->GetLocations();
3994
3995  if (instruction->GetResultType() == Primitive::kPrimInt) {
3996    Register first = locations->InAt(0).AsRegister<Register>();
3997    Register second = locations->InAt(1).AsRegister<Register>();
3998    Register out = locations->Out().AsRegister<Register>();
3999    if (instruction->IsAnd()) {
4000      __ and_(out, first, ShifterOperand(second));
4001    } else if (instruction->IsOr()) {
4002      __ orr(out, first, ShifterOperand(second));
4003    } else {
4004      DCHECK(instruction->IsXor());
4005      __ eor(out, first, ShifterOperand(second));
4006    }
4007  } else {
4008    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4009    Location first = locations->InAt(0);
4010    Location second = locations->InAt(1);
4011    Location out = locations->Out();
4012    if (instruction->IsAnd()) {
4013      __ and_(out.AsRegisterPairLow<Register>(),
4014              first.AsRegisterPairLow<Register>(),
4015              ShifterOperand(second.AsRegisterPairLow<Register>()));
4016      __ and_(out.AsRegisterPairHigh<Register>(),
4017              first.AsRegisterPairHigh<Register>(),
4018              ShifterOperand(second.AsRegisterPairHigh<Register>()));
4019    } else if (instruction->IsOr()) {
4020      __ orr(out.AsRegisterPairLow<Register>(),
4021             first.AsRegisterPairLow<Register>(),
4022             ShifterOperand(second.AsRegisterPairLow<Register>()));
4023      __ orr(out.AsRegisterPairHigh<Register>(),
4024             first.AsRegisterPairHigh<Register>(),
4025             ShifterOperand(second.AsRegisterPairHigh<Register>()));
4026    } else {
4027      DCHECK(instruction->IsXor());
4028      __ eor(out.AsRegisterPairLow<Register>(),
4029             first.AsRegisterPairLow<Register>(),
4030             ShifterOperand(second.AsRegisterPairLow<Register>()));
4031      __ eor(out.AsRegisterPairHigh<Register>(),
4032             first.AsRegisterPairHigh<Register>(),
4033             ShifterOperand(second.AsRegisterPairHigh<Register>()));
4034    }
4035  }
4036}
4037
4038void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
4039  DCHECK_EQ(temp, kArtMethodRegister);
4040
4041  // TODO: Implement all kinds of calls:
4042  // 1) boot -> boot
4043  // 2) app -> boot
4044  // 3) app -> app
4045  //
4046  // Currently we implement the app -> app logic, which looks up in the resolve cache.
4047
4048  // temp = method;
4049  LoadCurrentMethod(temp);
4050  if (!invoke->IsRecursive()) {
4051    // temp = temp->dex_cache_resolved_methods_;
4052    __ LoadFromOffset(
4053        kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
4054    // temp = temp[index_in_cache]
4055    __ LoadFromOffset(
4056        kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
4057    // LR = temp[offset_of_quick_compiled_code]
4058    __ LoadFromOffset(kLoadWord, LR, temp,
4059                      mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4060                          kArmWordSize).Int32Value());
4061    // LR()
4062    __ blx(LR);
4063  } else {
4064    __ bl(GetFrameEntryLabel());
4065  }
4066
4067  DCHECK(!IsLeafMethod());
4068}
4069
4070void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4071  // Nothing to do, this should be removed during prepare for register allocator.
4072  UNUSED(instruction);
4073  LOG(FATAL) << "Unreachable";
4074}
4075
4076void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4077  // Nothing to do, this should be removed during prepare for register allocator.
4078  UNUSED(instruction);
4079  LOG(FATAL) << "Unreachable";
4080}
4081
4082}  // namespace arm
4083}  // namespace art
4084