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