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