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