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