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