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