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