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