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