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