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