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