code_generator_arm.cc revision 8e3964b766652a0478e8e0e303e8556c997675f1
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 "entrypoints/quick/quick_entrypoints.h"
20#include "gc/accounting/card_table.h"
21#include "mirror/array-inl.h"
22#include "mirror/art_method.h"
23#include "mirror/class.h"
24#include "thread.h"
25#include "utils/assembler.h"
26#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
28#include "utils/stack_checks.h"
29
30namespace art {
31
32namespace arm {
33
34static SRegister FromDToLowS(DRegister reg) {
35  return static_cast<SRegister>(reg * 2);
36}
37
38static constexpr bool kExplicitStackOverflowCheck = false;
39
40static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2;  // LR, R6, R7
41static constexpr int kCurrentMethodStackOffset = 0;
42
43static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
44static constexpr size_t kRuntimeParameterCoreRegistersLength =
45    arraysize(kRuntimeParameterCoreRegisters);
46static constexpr DRegister kRuntimeParameterFpuRegisters[] = { };
47static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
48
49class InvokeRuntimeCallingConvention : public CallingConvention<Register, DRegister> {
50 public:
51  InvokeRuntimeCallingConvention()
52      : CallingConvention(kRuntimeParameterCoreRegisters,
53                          kRuntimeParameterCoreRegistersLength,
54                          kRuntimeParameterFpuRegisters,
55                          kRuntimeParameterFpuRegistersLength) {}
56
57 private:
58  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
59};
60
61#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
62
63class SlowPathCodeARM : public SlowPathCode {
64 public:
65  SlowPathCodeARM() : entry_label_(), exit_label_() {}
66
67  Label* GetEntryLabel() { return &entry_label_; }
68  Label* GetExitLabel() { return &exit_label_; }
69
70 private:
71  Label entry_label_;
72  Label exit_label_;
73
74  DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
75};
76
77class NullCheckSlowPathARM : public SlowPathCodeARM {
78 public:
79  explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
80
81  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
82    __ Bind(GetEntryLabel());
83    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
84    __ LoadFromOffset(kLoadWord, LR, TR, offset);
85    __ blx(LR);
86    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
87  }
88
89 private:
90  HNullCheck* const instruction_;
91  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
92};
93
94class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
95 public:
96  StackOverflowCheckSlowPathARM() {}
97
98  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
99    __ Bind(GetEntryLabel());
100    __ LoadFromOffset(kLoadWord, PC, TR,
101        QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
102  }
103
104 private:
105  DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
106};
107
108class SuspendCheckSlowPathARM : public SlowPathCodeARM {
109 public:
110  explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
111      : instruction_(instruction), successor_(successor) {}
112
113  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
114    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
115    __ Bind(GetEntryLabel());
116    codegen->SaveLiveRegisters(instruction_->GetLocations());
117    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
118    __ LoadFromOffset(kLoadWord, LR, TR, offset);
119    __ blx(LR);
120    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
121    codegen->RestoreLiveRegisters(instruction_->GetLocations());
122    if (successor_ == nullptr) {
123      __ b(GetReturnLabel());
124    } else {
125      __ b(arm_codegen->GetLabelOf(successor_));
126    }
127  }
128
129  Label* GetReturnLabel() {
130    DCHECK(successor_ == nullptr);
131    return &return_label_;
132  }
133
134 private:
135  HSuspendCheck* const instruction_;
136  // If not null, the block to branch to after the suspend check.
137  HBasicBlock* const successor_;
138
139  // If `successor_` is null, the label to branch to after the suspend check.
140  Label return_label_;
141
142  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
143};
144
145class BoundsCheckSlowPathARM : public SlowPathCodeARM {
146 public:
147  BoundsCheckSlowPathARM(HBoundsCheck* instruction,
148                         Location index_location,
149                         Location length_location)
150      : instruction_(instruction),
151        index_location_(index_location),
152        length_location_(length_location) {}
153
154  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
155    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
156    __ Bind(GetEntryLabel());
157    InvokeRuntimeCallingConvention calling_convention;
158    arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
159    arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
160    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
161    __ LoadFromOffset(kLoadWord, LR, TR, offset);
162    __ blx(LR);
163    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
164  }
165
166 private:
167  HBoundsCheck* const instruction_;
168  const Location index_location_;
169  const Location length_location_;
170
171  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
172};
173
174#undef __
175#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
176
177inline Condition ARMCondition(IfCondition cond) {
178  switch (cond) {
179    case kCondEQ: return EQ;
180    case kCondNE: return NE;
181    case kCondLT: return LT;
182    case kCondLE: return LE;
183    case kCondGT: return GT;
184    case kCondGE: return GE;
185    default:
186      LOG(FATAL) << "Unknown if condition";
187  }
188  return EQ;        // Unreachable.
189}
190
191inline Condition ARMOppositeCondition(IfCondition cond) {
192  switch (cond) {
193    case kCondEQ: return NE;
194    case kCondNE: return EQ;
195    case kCondLT: return GE;
196    case kCondLE: return GT;
197    case kCondGT: return LE;
198    case kCondGE: return LT;
199    default:
200      LOG(FATAL) << "Unknown if condition";
201  }
202  return EQ;        // Unreachable.
203}
204
205void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
206  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
207}
208
209void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
210  stream << ArmManagedRegister::FromDRegister(DRegister(reg));
211}
212
213void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
214  __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
215}
216
217void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
218  __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
219}
220
221CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
222    : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfDRegisters, kNumberOfRegisterPairs),
223      block_labels_(graph->GetArena(), 0),
224      location_builder_(graph, this),
225      instruction_visitor_(graph, this),
226      move_resolver_(graph->GetArena(), this),
227      assembler_(true) {}
228
229size_t CodeGeneratorARM::FrameEntrySpillSize() const {
230  return kNumberOfPushedRegistersAtEntry * kArmWordSize;
231}
232
233Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
234  switch (type) {
235    case Primitive::kPrimLong: {
236      size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
237      ArmManagedRegister pair =
238          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
239      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
240      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
241
242      blocked_core_registers_[pair.AsRegisterPairLow()] = true;
243      blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
244      UpdateBlockedPairRegisters();
245      return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
246    }
247
248    case Primitive::kPrimByte:
249    case Primitive::kPrimBoolean:
250    case Primitive::kPrimChar:
251    case Primitive::kPrimShort:
252    case Primitive::kPrimInt:
253    case Primitive::kPrimNot: {
254      int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
255      // Block all register pairs that contain `reg`.
256      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
257        ArmManagedRegister current =
258            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
259        if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
260          blocked_register_pairs_[i] = true;
261        }
262      }
263      return Location::RegisterLocation(reg);
264    }
265
266    case Primitive::kPrimFloat:
267    case Primitive::kPrimDouble: {
268      int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfDRegisters);
269      return Location::FpuRegisterLocation(reg);
270    }
271
272    case Primitive::kPrimVoid:
273      LOG(FATAL) << "Unreachable type " << type;
274  }
275
276  return Location();
277}
278
279void CodeGeneratorARM::SetupBlockedRegisters() const {
280  // Don't allocate the dalvik style register pair passing.
281  blocked_register_pairs_[R1_R2] = true;
282
283  // Stack register, LR and PC are always reserved.
284  blocked_core_registers_[SP] = true;
285  blocked_core_registers_[LR] = true;
286  blocked_core_registers_[PC] = true;
287
288  // Reserve R4 for suspend check.
289  blocked_core_registers_[R4] = true;
290
291  // Reserve thread register.
292  blocked_core_registers_[TR] = true;
293
294  // Reserve temp register.
295  blocked_core_registers_[IP] = true;
296
297  // TODO: We currently don't use Quick's callee saved registers.
298  // We always save and restore R6 and R7 to make sure we can use three
299  // register pairs for long operations.
300  blocked_core_registers_[R5] = true;
301  blocked_core_registers_[R8] = true;
302  blocked_core_registers_[R10] = true;
303  blocked_core_registers_[R11] = true;
304
305  blocked_fpu_registers_[D8] = true;
306  blocked_fpu_registers_[D9] = true;
307  blocked_fpu_registers_[D10] = true;
308  blocked_fpu_registers_[D11] = true;
309  blocked_fpu_registers_[D12] = true;
310  blocked_fpu_registers_[D13] = true;
311  blocked_fpu_registers_[D14] = true;
312  blocked_fpu_registers_[D15] = true;
313
314  UpdateBlockedPairRegisters();
315}
316
317void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
318  for (int i = 0; i < kNumberOfRegisterPairs; i++) {
319    ArmManagedRegister current =
320        ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
321    if (blocked_core_registers_[current.AsRegisterPairLow()]
322        || blocked_core_registers_[current.AsRegisterPairHigh()]) {
323      blocked_register_pairs_[i] = true;
324    }
325  }
326}
327
328InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
329      : HGraphVisitor(graph),
330        assembler_(codegen->GetAssembler()),
331        codegen_(codegen) {}
332
333void CodeGeneratorARM::GenerateFrameEntry() {
334  bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
335  if (!skip_overflow_check) {
336    if (kExplicitStackOverflowCheck) {
337      SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
338      AddSlowPath(slow_path);
339
340      __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
341      __ cmp(SP, ShifterOperand(IP));
342      __ b(slow_path->GetEntryLabel(), CC);
343    } else {
344      __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
345      __ LoadFromOffset(kLoadWord, IP, IP, 0);
346      RecordPcInfo(nullptr, 0);
347    }
348  }
349
350  core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
351  __ PushList(1 << LR | 1 << R6 | 1 << R7);
352
353  // The return PC has already been pushed on the stack.
354  __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
355  __ StoreToOffset(kStoreWord, R0, SP, 0);
356}
357
358void CodeGeneratorARM::GenerateFrameExit() {
359  __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
360  __ PopList(1 << PC | 1 << R6 | 1 << R7);
361}
362
363void CodeGeneratorARM::Bind(HBasicBlock* block) {
364  __ Bind(GetLabelOf(block));
365}
366
367Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
368  switch (load->GetType()) {
369    case Primitive::kPrimLong:
370    case Primitive::kPrimDouble:
371      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
372      break;
373
374    case Primitive::kPrimInt:
375    case Primitive::kPrimNot:
376    case Primitive::kPrimFloat:
377      return Location::StackSlot(GetStackSlot(load->GetLocal()));
378
379    case Primitive::kPrimBoolean:
380    case Primitive::kPrimByte:
381    case Primitive::kPrimChar:
382    case Primitive::kPrimShort:
383    case Primitive::kPrimVoid:
384      LOG(FATAL) << "Unexpected type " << load->GetType();
385  }
386
387  LOG(FATAL) << "Unreachable";
388  return Location();
389}
390
391Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
392  switch (type) {
393    case Primitive::kPrimBoolean:
394    case Primitive::kPrimByte:
395    case Primitive::kPrimChar:
396    case Primitive::kPrimShort:
397    case Primitive::kPrimInt:
398    case Primitive::kPrimFloat:
399    case Primitive::kPrimNot: {
400      uint32_t index = gp_index_++;
401      if (index < calling_convention.GetNumberOfRegisters()) {
402        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
403      } else {
404        return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
405      }
406    }
407
408    case Primitive::kPrimLong:
409    case Primitive::kPrimDouble: {
410      uint32_t index = gp_index_;
411      gp_index_ += 2;
412      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
413        ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
414            calling_convention.GetRegisterPairAt(index));
415        return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
416      } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
417        return Location::QuickParameter(index);
418      } else {
419        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
420      }
421    }
422
423    case Primitive::kPrimVoid:
424      LOG(FATAL) << "Unexpected parameter type " << type;
425      break;
426  }
427  return Location();
428}
429
430void CodeGeneratorARM::Move32(Location destination, Location source) {
431  if (source.Equals(destination)) {
432    return;
433  }
434  if (destination.IsRegister()) {
435    if (source.IsRegister()) {
436      __ Mov(destination.As<Register>(), source.As<Register>());
437    } else if (source.IsFpuRegister()) {
438      __ vmovrs(destination.As<Register>(), FromDToLowS(source.As<DRegister>()));
439    } else {
440      __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex());
441    }
442  } else if (destination.IsFpuRegister()) {
443    if (source.IsRegister()) {
444      __ vmovsr(FromDToLowS(destination.As<DRegister>()), source.As<Register>());
445    } else if (source.IsFpuRegister()) {
446      __ vmovs(FromDToLowS(destination.As<DRegister>()), FromDToLowS(source.As<DRegister>()));
447    } else {
448      __ vldrs(FromDToLowS(destination.As<DRegister>()), Address(SP, source.GetStackIndex()));
449    }
450  } else {
451    DCHECK(destination.IsStackSlot());
452    if (source.IsRegister()) {
453      __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex());
454    } else if (source.IsFpuRegister()) {
455      __ vstrs(FromDToLowS(source.As<DRegister>()), Address(SP, destination.GetStackIndex()));
456    } else {
457      DCHECK(source.IsStackSlot());
458      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
459      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
460    }
461  }
462}
463
464void CodeGeneratorARM::Move64(Location destination, Location source) {
465  if (source.Equals(destination)) {
466    return;
467  }
468  if (destination.IsRegisterPair()) {
469    if (source.IsRegisterPair()) {
470      __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
471      __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
472    } else if (source.IsFpuRegister()) {
473      LOG(FATAL) << "Unimplemented";
474    } else if (source.IsQuickParameter()) {
475      uint32_t argument_index = source.GetQuickParameterIndex();
476      InvokeDexCallingConvention calling_convention;
477      __ Mov(destination.AsRegisterPairLow<Register>(),
478             calling_convention.GetRegisterAt(argument_index));
479      __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(),
480             SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize());
481    } else {
482      DCHECK(source.IsDoubleStackSlot());
483      if (destination.AsRegisterPairLow<Register>() == R1) {
484        DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
485        __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
486        __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
487      } else {
488        __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
489                          SP, source.GetStackIndex());
490      }
491    }
492  } else if (destination.IsFpuRegister()) {
493    if (source.IsDoubleStackSlot()) {
494      __ vldrd(destination.As<DRegister>(), Address(SP, source.GetStackIndex()));
495    } else {
496      LOG(FATAL) << "Unimplemented";
497    }
498  } else if (destination.IsQuickParameter()) {
499    InvokeDexCallingConvention calling_convention;
500    uint32_t argument_index = destination.GetQuickParameterIndex();
501    if (source.IsRegisterPair()) {
502      __ Mov(calling_convention.GetRegisterAt(argument_index),
503             source.AsRegisterPairLow<Register>());
504      __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(),
505             SP, calling_convention.GetStackOffsetOf(argument_index + 1));
506    } else if (source.IsFpuRegister()) {
507      LOG(FATAL) << "Unimplemented";
508    } else {
509      DCHECK(source.IsDoubleStackSlot());
510      __ LoadFromOffset(kLoadWord, calling_convention.GetRegisterAt(argument_index), SP, source.GetStackIndex());
511      __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize));
512      __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(argument_index + 1));
513    }
514  } else {
515    DCHECK(destination.IsDoubleStackSlot());
516    if (source.IsRegisterPair()) {
517      if (source.AsRegisterPairLow<Register>() == R1) {
518        DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
519        __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
520        __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
521      } else {
522        __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
523                         SP, destination.GetStackIndex());
524      }
525    } else if (source.IsQuickParameter()) {
526      InvokeDexCallingConvention calling_convention;
527      uint32_t argument_index = source.GetQuickParameterIndex();
528      __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(argument_index),
529             SP, destination.GetStackIndex());
530      __ LoadFromOffset(kLoadWord, R0,
531             SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize());
532      __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize));
533    } else if (source.IsFpuRegister()) {
534      __ vstrd(source.As<DRegister>(), Address(SP, destination.GetStackIndex()));
535    } else {
536      DCHECK(source.IsDoubleStackSlot());
537      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
538      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
539      __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
540      __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
541    }
542  }
543}
544
545void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
546  LocationSummary* locations = instruction->GetLocations();
547  if (locations != nullptr && locations->Out().Equals(location)) {
548    return;
549  }
550
551  if (instruction->IsIntConstant()) {
552    int32_t value = instruction->AsIntConstant()->GetValue();
553    if (location.IsRegister()) {
554      __ LoadImmediate(location.As<Register>(), value);
555    } else {
556      DCHECK(location.IsStackSlot());
557      __ LoadImmediate(IP, value);
558      __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
559    }
560  } else if (instruction->IsLongConstant()) {
561    int64_t value = instruction->AsLongConstant()->GetValue();
562    if (location.IsRegisterPair()) {
563      __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
564      __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
565    } else {
566      DCHECK(location.IsDoubleStackSlot());
567      __ LoadImmediate(IP, Low32Bits(value));
568      __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
569      __ LoadImmediate(IP, High32Bits(value));
570      __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
571    }
572  } else if (instruction->IsLoadLocal()) {
573    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
574    switch (instruction->GetType()) {
575      case Primitive::kPrimBoolean:
576      case Primitive::kPrimByte:
577      case Primitive::kPrimChar:
578      case Primitive::kPrimShort:
579      case Primitive::kPrimInt:
580      case Primitive::kPrimNot:
581      case Primitive::kPrimFloat:
582        Move32(location, Location::StackSlot(stack_slot));
583        break;
584
585      case Primitive::kPrimLong:
586      case Primitive::kPrimDouble:
587        Move64(location, Location::DoubleStackSlot(stack_slot));
588        break;
589
590      default:
591        LOG(FATAL) << "Unexpected type " << instruction->GetType();
592    }
593  } else {
594    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
595    switch (instruction->GetType()) {
596      case Primitive::kPrimBoolean:
597      case Primitive::kPrimByte:
598      case Primitive::kPrimChar:
599      case Primitive::kPrimShort:
600      case Primitive::kPrimNot:
601      case Primitive::kPrimInt:
602      case Primitive::kPrimFloat:
603        Move32(location, locations->Out());
604        break;
605
606      case Primitive::kPrimLong:
607      case Primitive::kPrimDouble:
608        Move64(location, locations->Out());
609        break;
610
611      default:
612        LOG(FATAL) << "Unexpected type " << instruction->GetType();
613    }
614  }
615}
616
617void LocationsBuilderARM::VisitGoto(HGoto* got) {
618  got->SetLocations(nullptr);
619}
620
621void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
622  HBasicBlock* successor = got->GetSuccessor();
623  DCHECK(!successor->IsExitBlock());
624
625  HBasicBlock* block = got->GetBlock();
626  HInstruction* previous = got->GetPrevious();
627
628  HLoopInformation* info = block->GetLoopInformation();
629  if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
630    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
631    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
632    return;
633  }
634
635  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
636    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
637  }
638  if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
639    __ b(codegen_->GetLabelOf(successor));
640  }
641}
642
643void LocationsBuilderARM::VisitExit(HExit* exit) {
644  exit->SetLocations(nullptr);
645}
646
647void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
648  if (kIsDebugBuild) {
649    __ Comment("Unreachable");
650    __ bkpt(0);
651  }
652}
653
654void LocationsBuilderARM::VisitIf(HIf* if_instr) {
655  LocationSummary* locations =
656      new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
657  HInstruction* cond = if_instr->InputAt(0);
658  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
659    locations->SetInAt(0, Location::RequiresRegister());
660  }
661}
662
663void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
664  HInstruction* cond = if_instr->InputAt(0);
665  if (cond->IsIntConstant()) {
666    // Constant condition, statically compared against 1.
667    int32_t cond_value = cond->AsIntConstant()->GetValue();
668    if (cond_value == 1) {
669      if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
670                                     if_instr->IfTrueSuccessor())) {
671        __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
672      }
673      return;
674    } else {
675      DCHECK_EQ(cond_value, 0);
676    }
677  } else {
678    if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
679      // Condition has been materialized, compare the output to 0
680      DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
681      __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
682             ShifterOperand(0));
683      __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
684    } else {
685      // Condition has not been materialized, use its inputs as the
686      // comparison and its condition as the branch condition.
687      LocationSummary* locations = cond->GetLocations();
688      if (locations->InAt(1).IsRegister()) {
689        __ cmp(locations->InAt(0).As<Register>(),
690               ShifterOperand(locations->InAt(1).As<Register>()));
691      } else {
692        DCHECK(locations->InAt(1).IsConstant());
693        int32_t value =
694            locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
695        ShifterOperand operand;
696        if (ShifterOperand::CanHoldArm(value, &operand)) {
697          __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
698        } else {
699          Register temp = IP;
700          __ LoadImmediate(temp, value);
701          __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
702        }
703      }
704      __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
705           ARMCondition(cond->AsCondition()->GetCondition()));
706    }
707  }
708  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
709                                 if_instr->IfFalseSuccessor())) {
710    __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
711  }
712}
713
714
715void LocationsBuilderARM::VisitCondition(HCondition* comp) {
716  LocationSummary* locations =
717      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
718  locations->SetInAt(0, Location::RequiresRegister());
719  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
720  if (comp->NeedsMaterialization()) {
721    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
722  }
723}
724
725void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
726  if (!comp->NeedsMaterialization()) return;
727
728  LocationSummary* locations = comp->GetLocations();
729  if (locations->InAt(1).IsRegister()) {
730    __ cmp(locations->InAt(0).As<Register>(),
731           ShifterOperand(locations->InAt(1).As<Register>()));
732  } else {
733    DCHECK(locations->InAt(1).IsConstant());
734    int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
735    ShifterOperand operand;
736    if (ShifterOperand::CanHoldArm(value, &operand)) {
737      __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
738    } else {
739      Register temp = IP;
740      __ LoadImmediate(temp, value);
741      __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
742    }
743  }
744  __ it(ARMCondition(comp->GetCondition()), kItElse);
745  __ mov(locations->Out().As<Register>(), ShifterOperand(1),
746         ARMCondition(comp->GetCondition()));
747  __ mov(locations->Out().As<Register>(), ShifterOperand(0),
748         ARMOppositeCondition(comp->GetCondition()));
749}
750
751void LocationsBuilderARM::VisitEqual(HEqual* comp) {
752  VisitCondition(comp);
753}
754
755void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
756  VisitCondition(comp);
757}
758
759void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
760  VisitCondition(comp);
761}
762
763void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
764  VisitCondition(comp);
765}
766
767void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
768  VisitCondition(comp);
769}
770
771void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
772  VisitCondition(comp);
773}
774
775void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
776  VisitCondition(comp);
777}
778
779void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
780  VisitCondition(comp);
781}
782
783void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
784  VisitCondition(comp);
785}
786
787void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
788  VisitCondition(comp);
789}
790
791void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
792  VisitCondition(comp);
793}
794
795void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
796  VisitCondition(comp);
797}
798
799void LocationsBuilderARM::VisitLocal(HLocal* local) {
800  local->SetLocations(nullptr);
801}
802
803void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
804  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
805}
806
807void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
808  load->SetLocations(nullptr);
809}
810
811void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
812  // Nothing to do, this is driven by the code generator.
813}
814
815void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
816  LocationSummary* locations =
817      new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
818  switch (store->InputAt(1)->GetType()) {
819    case Primitive::kPrimBoolean:
820    case Primitive::kPrimByte:
821    case Primitive::kPrimChar:
822    case Primitive::kPrimShort:
823    case Primitive::kPrimInt:
824    case Primitive::kPrimNot:
825    case Primitive::kPrimFloat:
826      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
827      break;
828
829    case Primitive::kPrimLong:
830    case Primitive::kPrimDouble:
831      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
832      break;
833
834    default:
835      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
836  }
837}
838
839void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
840}
841
842void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
843  LocationSummary* locations =
844      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
845  locations->SetOut(Location::ConstantLocation(constant));
846}
847
848void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
849  // Will be generated at use site.
850}
851
852void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
853  LocationSummary* locations =
854      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
855  locations->SetOut(Location::ConstantLocation(constant));
856}
857
858void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
859  // Will be generated at use site.
860}
861
862void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
863  ret->SetLocations(nullptr);
864}
865
866void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
867  codegen_->GenerateFrameExit();
868}
869
870void LocationsBuilderARM::VisitReturn(HReturn* ret) {
871  LocationSummary* locations =
872      new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
873  switch (ret->InputAt(0)->GetType()) {
874    case Primitive::kPrimBoolean:
875    case Primitive::kPrimByte:
876    case Primitive::kPrimChar:
877    case Primitive::kPrimShort:
878    case Primitive::kPrimInt:
879    case Primitive::kPrimNot:
880    case Primitive::kPrimFloat:
881      locations->SetInAt(0, Location::RegisterLocation(R0));
882      break;
883
884    case Primitive::kPrimLong:
885    case Primitive::kPrimDouble:
886      locations->SetInAt(0, Location::RegisterPairLocation(R0, R1));
887      break;
888
889    default:
890      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
891  }
892}
893
894void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
895  if (kIsDebugBuild) {
896    switch (ret->InputAt(0)->GetType()) {
897      case Primitive::kPrimBoolean:
898      case Primitive::kPrimByte:
899      case Primitive::kPrimChar:
900      case Primitive::kPrimShort:
901      case Primitive::kPrimInt:
902      case Primitive::kPrimNot:
903      case Primitive::kPrimFloat:
904        DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0);
905        break;
906
907      case Primitive::kPrimLong:
908      case Primitive::kPrimDouble:
909        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0);
910        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1);
911        break;
912
913      default:
914        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
915    }
916  }
917  codegen_->GenerateFrameExit();
918}
919
920void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
921  HandleInvoke(invoke);
922}
923
924void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
925  __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
926}
927
928void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
929  Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
930  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
931  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
932      invoke->GetIndexInDexCache() * kArmWordSize;
933
934  // TODO: Implement all kinds of calls:
935  // 1) boot -> boot
936  // 2) app -> boot
937  // 3) app -> app
938  //
939  // Currently we implement the app -> app logic, which looks up in the resolve cache.
940
941  // temp = method;
942  LoadCurrentMethod(temp);
943  // temp = temp->dex_cache_resolved_methods_;
944  __ LoadFromOffset(kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
945  // temp = temp[index_in_cache]
946  __ LoadFromOffset(kLoadWord, temp, temp, index_in_cache);
947  // LR = temp[offset_of_quick_compiled_code]
948  __ LoadFromOffset(kLoadWord, LR, temp,
949                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
950  // LR()
951  __ blx(LR);
952
953  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
954  DCHECK(!codegen_->IsLeafMethod());
955}
956
957void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
958  HandleInvoke(invoke);
959}
960
961void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
962  LocationSummary* locations =
963      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
964  locations->AddTemp(Location::RegisterLocation(R0));
965
966  InvokeDexCallingConventionVisitor calling_convention_visitor;
967  for (size_t i = 0; i < invoke->InputCount(); i++) {
968    HInstruction* input = invoke->InputAt(i);
969    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
970  }
971
972  switch (invoke->GetType()) {
973    case Primitive::kPrimBoolean:
974    case Primitive::kPrimByte:
975    case Primitive::kPrimChar:
976    case Primitive::kPrimShort:
977    case Primitive::kPrimInt:
978    case Primitive::kPrimNot:
979    case Primitive::kPrimFloat:
980      locations->SetOut(Location::RegisterLocation(R0));
981      break;
982
983    case Primitive::kPrimLong:
984    case Primitive::kPrimDouble:
985      locations->SetOut(Location::RegisterPairLocation(R0, R1));
986      break;
987
988    case Primitive::kPrimVoid:
989      break;
990  }
991}
992
993
994void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
995  Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
996  uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
997          invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
998  LocationSummary* locations = invoke->GetLocations();
999  Location receiver = locations->InAt(0);
1000  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1001  // temp = object->GetClass();
1002  if (receiver.IsStackSlot()) {
1003    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1004    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1005  } else {
1006    __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
1007  }
1008  // temp = temp->GetMethodAt(method_offset);
1009  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
1010  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1011  // LR = temp->GetEntryPoint();
1012  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1013  // LR();
1014  __ blx(LR);
1015  DCHECK(!codegen_->IsLeafMethod());
1016  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1017}
1018
1019void LocationsBuilderARM::VisitAdd(HAdd* add) {
1020  LocationSummary* locations =
1021      new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
1022  switch (add->GetResultType()) {
1023    case Primitive::kPrimInt:
1024    case Primitive::kPrimLong: {
1025      bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong);
1026      locations->SetInAt(0, Location::RequiresRegister());
1027      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1028      locations->SetOut(Location::RequiresRegister(), output_overlaps);
1029      break;
1030    }
1031
1032    case Primitive::kPrimFloat:
1033    case Primitive::kPrimDouble: {
1034      locations->SetInAt(0, Location::RequiresFpuRegister());
1035      locations->SetInAt(1, Location::RequiresFpuRegister());
1036      locations->SetOut(Location::RequiresFpuRegister());
1037      break;
1038    }
1039
1040    default:
1041      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1042  }
1043}
1044
1045void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1046  LocationSummary* locations = add->GetLocations();
1047  Location out = locations->Out();
1048  Location first = locations->InAt(0);
1049  Location second = locations->InAt(1);
1050  switch (add->GetResultType()) {
1051    case Primitive::kPrimInt:
1052      if (second.IsRegister()) {
1053        __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
1054      } else {
1055        __ AddConstant(out.As<Register>(),
1056                       first.As<Register>(),
1057                       second.GetConstant()->AsIntConstant()->GetValue());
1058      }
1059      break;
1060
1061    case Primitive::kPrimLong:
1062      __ adds(out.AsRegisterPairLow<Register>(),
1063              first.AsRegisterPairLow<Register>(),
1064              ShifterOperand(second.AsRegisterPairLow<Register>()));
1065      __ adc(out.AsRegisterPairHigh<Register>(),
1066             first.AsRegisterPairHigh<Register>(),
1067             ShifterOperand(second.AsRegisterPairHigh<Register>()));
1068      break;
1069
1070    case Primitive::kPrimFloat:
1071      __ vadds(FromDToLowS(out.As<DRegister>()),
1072               FromDToLowS(first.As<DRegister>()),
1073               FromDToLowS(second.As<DRegister>()));
1074      break;
1075
1076    case Primitive::kPrimDouble:
1077      __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
1078      break;
1079
1080    default:
1081      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1082  }
1083}
1084
1085void LocationsBuilderARM::VisitSub(HSub* sub) {
1086  LocationSummary* locations =
1087      new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
1088  switch (sub->GetResultType()) {
1089    case Primitive::kPrimInt:
1090    case Primitive::kPrimLong: {
1091      bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong);
1092      locations->SetInAt(0, Location::RequiresRegister());
1093      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
1094      locations->SetOut(Location::RequiresRegister(), output_overlaps);
1095      break;
1096    }
1097
1098    case Primitive::kPrimBoolean:
1099    case Primitive::kPrimByte:
1100    case Primitive::kPrimChar:
1101    case Primitive::kPrimShort:
1102      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1103      break;
1104
1105    default:
1106      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1107  }
1108}
1109
1110void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1111  LocationSummary* locations = sub->GetLocations();
1112  switch (sub->GetResultType()) {
1113    case Primitive::kPrimInt: {
1114      if (locations->InAt(1).IsRegister()) {
1115        __ sub(locations->Out().As<Register>(),
1116               locations->InAt(0).As<Register>(),
1117               ShifterOperand(locations->InAt(1).As<Register>()));
1118      } else {
1119        __ AddConstant(locations->Out().As<Register>(),
1120                       locations->InAt(0).As<Register>(),
1121                       -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1122      }
1123      break;
1124    }
1125
1126    case Primitive::kPrimLong:
1127      __ subs(locations->Out().AsRegisterPairLow<Register>(),
1128              locations->InAt(0).AsRegisterPairLow<Register>(),
1129              ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
1130      __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
1131             locations->InAt(0).AsRegisterPairHigh<Register>(),
1132             ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
1133      break;
1134
1135    case Primitive::kPrimBoolean:
1136    case Primitive::kPrimByte:
1137    case Primitive::kPrimChar:
1138    case Primitive::kPrimShort:
1139      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1140      break;
1141
1142    default:
1143      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
1144  }
1145}
1146
1147void LocationsBuilderARM::VisitMul(HMul* mul) {
1148  LocationSummary* locations =
1149      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1150  switch (mul->GetResultType()) {
1151    case Primitive::kPrimInt:
1152    case Primitive::kPrimLong:  {
1153      locations->SetInAt(0, Location::RequiresRegister());
1154      locations->SetInAt(1, Location::RequiresRegister());
1155      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1156      break;
1157    }
1158
1159    case Primitive::kPrimBoolean:
1160    case Primitive::kPrimByte:
1161    case Primitive::kPrimChar:
1162    case Primitive::kPrimShort:
1163      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1164      break;
1165
1166    default:
1167      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
1168  }
1169}
1170
1171void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
1172  LocationSummary* locations = mul->GetLocations();
1173  Location out = locations->Out();
1174  Location first = locations->InAt(0);
1175  Location second = locations->InAt(1);
1176  switch (mul->GetResultType()) {
1177    case Primitive::kPrimInt: {
1178      __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>());
1179      break;
1180    }
1181    case Primitive::kPrimLong: {
1182      Register out_hi = out.AsRegisterPairHigh<Register>();
1183      Register out_lo = out.AsRegisterPairLow<Register>();
1184      Register in1_hi = first.AsRegisterPairHigh<Register>();
1185      Register in1_lo = first.AsRegisterPairLow<Register>();
1186      Register in2_hi = second.AsRegisterPairHigh<Register>();
1187      Register in2_lo = second.AsRegisterPairLow<Register>();
1188
1189      // Extra checks to protect caused by the existence of R1_R2.
1190      // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
1191      // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
1192      DCHECK_NE(out_hi, in1_lo);
1193      DCHECK_NE(out_hi, in2_lo);
1194
1195      // input: in1 - 64 bits, in2 - 64 bits
1196      // output: out
1197      // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
1198      // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
1199      // parts: out.lo = (in1.lo * in2.lo)[31:0]
1200
1201      // IP <- in1.lo * in2.hi
1202      __ mul(IP, in1_lo, in2_hi);
1203      // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
1204      __ mla(out_hi, in1_hi, in2_lo, IP);
1205      // out.lo <- (in1.lo * in2.lo)[31:0];
1206      __ umull(out_lo, IP, in1_lo, in2_lo);
1207      // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
1208      __ add(out_hi, out_hi, ShifterOperand(IP));
1209      break;
1210    }
1211    case Primitive::kPrimBoolean:
1212    case Primitive::kPrimByte:
1213    case Primitive::kPrimChar:
1214    case Primitive::kPrimShort:
1215      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1216      break;
1217
1218    default:
1219      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
1220  }
1221}
1222
1223void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
1224  LocationSummary* locations =
1225      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1226  InvokeRuntimeCallingConvention calling_convention;
1227  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1228  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1229  locations->SetOut(Location::RegisterLocation(R0));
1230}
1231
1232void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1233  InvokeRuntimeCallingConvention calling_convention;
1234  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1235  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1236
1237  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
1238  __ LoadFromOffset(kLoadWord, LR, TR, offset);
1239  __ blx(LR);
1240
1241  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1242  DCHECK(!codegen_->IsLeafMethod());
1243}
1244
1245void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
1246  LocationSummary* locations =
1247      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1248  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1249  if (location.IsStackSlot()) {
1250    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1251  } else if (location.IsDoubleStackSlot()) {
1252    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1253  }
1254  locations->SetOut(location);
1255}
1256
1257void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
1258  // Nothing to do, the parameter is already at its location.
1259}
1260
1261void LocationsBuilderARM::VisitNot(HNot* instruction) {
1262  LocationSummary* locations =
1263      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1264  locations->SetInAt(0, Location::RequiresRegister());
1265  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1266}
1267
1268void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1269  LocationSummary* locations = instruction->GetLocations();
1270  __ eor(locations->Out().As<Register>(),
1271         locations->InAt(0).As<Register>(), ShifterOperand(1));
1272}
1273
1274void LocationsBuilderARM::VisitCompare(HCompare* compare) {
1275  LocationSummary* locations =
1276      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1277  locations->SetInAt(0, Location::RequiresRegister());
1278  locations->SetInAt(1, Location::RequiresRegister());
1279  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1280}
1281
1282void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1283  Label greater, done;
1284  LocationSummary* locations = compare->GetLocations();
1285  switch (compare->InputAt(0)->GetType()) {
1286    case Primitive::kPrimLong: {
1287      Register output = locations->Out().As<Register>();
1288      Location left = locations->InAt(0);
1289      Location right = locations->InAt(1);
1290      Label less, greater, done;
1291      __ cmp(left.AsRegisterPairHigh<Register>(),
1292             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
1293      __ b(&less, LT);
1294      __ b(&greater, GT);
1295      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1296      // the status flags.
1297      __ LoadImmediate(output, 0);
1298      __ cmp(left.AsRegisterPairLow<Register>(),
1299             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
1300      __ b(&done, EQ);
1301      __ b(&less, CC);
1302
1303      __ Bind(&greater);
1304      __ LoadImmediate(output, 1);
1305      __ b(&done);
1306
1307      __ Bind(&less);
1308      __ LoadImmediate(output, -1);
1309
1310      __ Bind(&done);
1311      break;
1312    }
1313    default:
1314      LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1315  }
1316}
1317
1318void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
1319  LocationSummary* locations =
1320      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1321  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1322    locations->SetInAt(i, Location::Any());
1323  }
1324  locations->SetOut(Location::Any());
1325}
1326
1327void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
1328  LOG(FATAL) << "Unreachable";
1329}
1330
1331void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1332  LocationSummary* locations =
1333      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1334  bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1335  locations->SetInAt(0, Location::RequiresRegister());
1336  locations->SetInAt(1, Location::RequiresRegister());
1337  // Temporary registers for the write barrier.
1338  if (is_object_type) {
1339    locations->AddTemp(Location::RequiresRegister());
1340    locations->AddTemp(Location::RequiresRegister());
1341  }
1342}
1343
1344void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1345  LocationSummary* locations = instruction->GetLocations();
1346  Register obj = locations->InAt(0).As<Register>();
1347  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1348  Primitive::Type field_type = instruction->GetFieldType();
1349
1350  switch (field_type) {
1351    case Primitive::kPrimBoolean:
1352    case Primitive::kPrimByte: {
1353      Register value = locations->InAt(1).As<Register>();
1354      __ StoreToOffset(kStoreByte, value, obj, offset);
1355      break;
1356    }
1357
1358    case Primitive::kPrimShort:
1359    case Primitive::kPrimChar: {
1360      Register value = locations->InAt(1).As<Register>();
1361      __ StoreToOffset(kStoreHalfword, value, obj, offset);
1362      break;
1363    }
1364
1365    case Primitive::kPrimInt:
1366    case Primitive::kPrimNot: {
1367      Register value = locations->InAt(1).As<Register>();
1368      __ StoreToOffset(kStoreWord, value, obj, offset);
1369      if (field_type == Primitive::kPrimNot) {
1370        Register temp = locations->GetTemp(0).As<Register>();
1371        Register card = locations->GetTemp(1).As<Register>();
1372        codegen_->MarkGCCard(temp, card, obj, value);
1373      }
1374      break;
1375    }
1376
1377    case Primitive::kPrimLong: {
1378      Location value = locations->InAt(1);
1379      __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
1380      break;
1381    }
1382
1383    case Primitive::kPrimFloat:
1384    case Primitive::kPrimDouble:
1385      LOG(FATAL) << "Unimplemented register type " << field_type;
1386      UNREACHABLE();
1387    case Primitive::kPrimVoid:
1388      LOG(FATAL) << "Unreachable type " << field_type;
1389      UNREACHABLE();
1390  }
1391}
1392
1393void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1394  LocationSummary* locations =
1395      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1396  locations->SetInAt(0, Location::RequiresRegister());
1397  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1398}
1399
1400void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1401  LocationSummary* locations = instruction->GetLocations();
1402  Register obj = locations->InAt(0).As<Register>();
1403  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1404
1405  switch (instruction->GetType()) {
1406    case Primitive::kPrimBoolean: {
1407      Register out = locations->Out().As<Register>();
1408      __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1409      break;
1410    }
1411
1412    case Primitive::kPrimByte: {
1413      Register out = locations->Out().As<Register>();
1414      __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1415      break;
1416    }
1417
1418    case Primitive::kPrimShort: {
1419      Register out = locations->Out().As<Register>();
1420      __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1421      break;
1422    }
1423
1424    case Primitive::kPrimChar: {
1425      Register out = locations->Out().As<Register>();
1426      __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1427      break;
1428    }
1429
1430    case Primitive::kPrimInt:
1431    case Primitive::kPrimNot: {
1432      Register out = locations->Out().As<Register>();
1433      __ LoadFromOffset(kLoadWord, out, obj, offset);
1434      break;
1435    }
1436
1437    case Primitive::kPrimLong: {
1438      // TODO: support volatile.
1439      Location out = locations->Out();
1440      __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
1441      break;
1442    }
1443
1444    case Primitive::kPrimFloat:
1445    case Primitive::kPrimDouble:
1446      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1447      UNREACHABLE();
1448    case Primitive::kPrimVoid:
1449      LOG(FATAL) << "Unreachable type " << instruction->GetType();
1450      UNREACHABLE();
1451  }
1452}
1453
1454void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1455  LocationSummary* locations =
1456      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1457  locations->SetInAt(0, Location::RequiresRegister());
1458  if (instruction->HasUses()) {
1459    locations->SetOut(Location::SameAsFirstInput());
1460  }
1461}
1462
1463void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1464  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
1465  codegen_->AddSlowPath(slow_path);
1466
1467  LocationSummary* locations = instruction->GetLocations();
1468  Location obj = locations->InAt(0);
1469
1470  if (obj.IsRegister()) {
1471    __ cmp(obj.As<Register>(), ShifterOperand(0));
1472    __ b(slow_path->GetEntryLabel(), EQ);
1473  } else {
1474    DCHECK(obj.IsConstant()) << obj;
1475    DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1476    __ b(slow_path->GetEntryLabel());
1477  }
1478}
1479
1480void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
1481  LocationSummary* locations =
1482      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1483  locations->SetInAt(0, Location::RequiresRegister());
1484  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1485  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1486}
1487
1488void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1489  LocationSummary* locations = instruction->GetLocations();
1490  Register obj = locations->InAt(0).As<Register>();
1491  Location index = locations->InAt(1);
1492
1493  switch (instruction->GetType()) {
1494    case Primitive::kPrimBoolean: {
1495      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1496      Register out = locations->Out().As<Register>();
1497      if (index.IsConstant()) {
1498        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1499        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1500      } else {
1501        __ add(IP, obj, ShifterOperand(index.As<Register>()));
1502        __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1503      }
1504      break;
1505    }
1506
1507    case Primitive::kPrimByte: {
1508      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1509      Register out = locations->Out().As<Register>();
1510      if (index.IsConstant()) {
1511        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1512        __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1513      } else {
1514        __ add(IP, obj, ShifterOperand(index.As<Register>()));
1515        __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1516      }
1517      break;
1518    }
1519
1520    case Primitive::kPrimShort: {
1521      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1522      Register out = locations->Out().As<Register>();
1523      if (index.IsConstant()) {
1524        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1525        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1526      } else {
1527        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
1528        __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1529      }
1530      break;
1531    }
1532
1533    case Primitive::kPrimChar: {
1534      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1535      Register out = locations->Out().As<Register>();
1536      if (index.IsConstant()) {
1537        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1538        __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1539      } else {
1540        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
1541        __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1542      }
1543      break;
1544    }
1545
1546    case Primitive::kPrimInt:
1547    case Primitive::kPrimNot: {
1548      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1549      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1550      Register out = locations->Out().As<Register>();
1551      if (index.IsConstant()) {
1552        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1553        __ LoadFromOffset(kLoadWord, out, obj, offset);
1554      } else {
1555        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
1556        __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1557      }
1558      break;
1559    }
1560
1561    case Primitive::kPrimLong: {
1562      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1563      Location out = locations->Out();
1564      if (index.IsConstant()) {
1565        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1566        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
1567      } else {
1568        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1569        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
1570      }
1571      break;
1572    }
1573
1574    case Primitive::kPrimFloat:
1575    case Primitive::kPrimDouble:
1576      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1577      UNREACHABLE();
1578    case Primitive::kPrimVoid:
1579      LOG(FATAL) << "Unreachable type " << instruction->GetType();
1580      UNREACHABLE();
1581  }
1582}
1583
1584void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
1585  Primitive::Type value_type = instruction->GetComponentType();
1586  bool is_object = value_type == Primitive::kPrimNot;
1587  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1588      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1589  if (is_object) {
1590    InvokeRuntimeCallingConvention calling_convention;
1591    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1592    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1593    locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1594  } else {
1595    locations->SetInAt(0, Location::RequiresRegister());
1596    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1597    locations->SetInAt(2, Location::RequiresRegister());
1598  }
1599}
1600
1601void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1602  LocationSummary* locations = instruction->GetLocations();
1603  Register obj = locations->InAt(0).As<Register>();
1604  Location index = locations->InAt(1);
1605  Primitive::Type value_type = instruction->GetComponentType();
1606
1607  switch (value_type) {
1608    case Primitive::kPrimBoolean:
1609    case Primitive::kPrimByte: {
1610      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1611      Register value = locations->InAt(2).As<Register>();
1612      if (index.IsConstant()) {
1613        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1614        __ StoreToOffset(kStoreByte, value, obj, offset);
1615      } else {
1616        __ add(IP, obj, ShifterOperand(index.As<Register>()));
1617        __ StoreToOffset(kStoreByte, value, IP, data_offset);
1618      }
1619      break;
1620    }
1621
1622    case Primitive::kPrimShort:
1623    case Primitive::kPrimChar: {
1624      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1625      Register value = locations->InAt(2).As<Register>();
1626      if (index.IsConstant()) {
1627        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1628        __ StoreToOffset(kStoreHalfword, value, obj, offset);
1629      } else {
1630        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
1631        __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1632      }
1633      break;
1634    }
1635
1636    case Primitive::kPrimInt: {
1637      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1638      Register value = locations->InAt(2).As<Register>();
1639      if (index.IsConstant()) {
1640        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1641        __ StoreToOffset(kStoreWord, value, obj, offset);
1642      } else {
1643        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
1644        __ StoreToOffset(kStoreWord, value, IP, data_offset);
1645      }
1646      break;
1647    }
1648
1649    case Primitive::kPrimNot: {
1650      int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1651      __ LoadFromOffset(kLoadWord, LR, TR, offset);
1652      __ blx(LR);
1653      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1654      DCHECK(!codegen_->IsLeafMethod());
1655      break;
1656    }
1657
1658    case Primitive::kPrimLong: {
1659      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1660      Location value = locations->InAt(2);
1661      if (index.IsConstant()) {
1662        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1663        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
1664      } else {
1665        __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1666        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
1667      }
1668      break;
1669    }
1670
1671    case Primitive::kPrimFloat:
1672    case Primitive::kPrimDouble:
1673      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1674      UNREACHABLE();
1675    case Primitive::kPrimVoid:
1676      LOG(FATAL) << "Unreachable type " << instruction->GetType();
1677      UNREACHABLE();
1678  }
1679}
1680
1681void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
1682  LocationSummary* locations =
1683      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1684  locations->SetInAt(0, Location::RequiresRegister());
1685  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1686}
1687
1688void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1689  LocationSummary* locations = instruction->GetLocations();
1690  uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1691  Register obj = locations->InAt(0).As<Register>();
1692  Register out = locations->Out().As<Register>();
1693  __ LoadFromOffset(kLoadWord, out, obj, offset);
1694}
1695
1696void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1697  LocationSummary* locations =
1698      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1699  locations->SetInAt(0, Location::RequiresRegister());
1700  locations->SetInAt(1, Location::RequiresRegister());
1701  if (instruction->HasUses()) {
1702    locations->SetOut(Location::SameAsFirstInput());
1703  }
1704}
1705
1706void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1707  LocationSummary* locations = instruction->GetLocations();
1708  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
1709      instruction, locations->InAt(0), locations->InAt(1));
1710  codegen_->AddSlowPath(slow_path);
1711
1712  Register index = locations->InAt(0).As<Register>();
1713  Register length = locations->InAt(1).As<Register>();
1714
1715  __ cmp(index, ShifterOperand(length));
1716  __ b(slow_path->GetEntryLabel(), CS);
1717}
1718
1719void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1720  Label is_null;
1721  __ CompareAndBranchIfZero(value, &is_null);
1722  __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1723  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1724  __ strb(card, Address(card, temp));
1725  __ Bind(&is_null);
1726}
1727
1728void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1729  temp->SetLocations(nullptr);
1730}
1731
1732void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1733  // Nothing to do, this is driven by the code generator.
1734}
1735
1736void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
1737  LOG(FATAL) << "Unreachable";
1738}
1739
1740void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
1741  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1742}
1743
1744void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1745  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1746}
1747
1748void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1749  HBasicBlock* block = instruction->GetBlock();
1750  if (block->GetLoopInformation() != nullptr) {
1751    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1752    // The back edge will generate the suspend check.
1753    return;
1754  }
1755  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1756    // The goto will generate the suspend check.
1757    return;
1758  }
1759  GenerateSuspendCheck(instruction, nullptr);
1760}
1761
1762void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1763                                                       HBasicBlock* successor) {
1764  SuspendCheckSlowPathARM* slow_path =
1765      new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
1766  codegen_->AddSlowPath(slow_path);
1767
1768  __ subs(R4, R4, ShifterOperand(1));
1769  if (successor == nullptr) {
1770    __ b(slow_path->GetEntryLabel(), EQ);
1771    __ Bind(slow_path->GetReturnLabel());
1772  } else {
1773    __ b(codegen_->GetLabelOf(successor), NE);
1774    __ b(slow_path->GetEntryLabel());
1775  }
1776}
1777
1778ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1779  return codegen_->GetAssembler();
1780}
1781
1782void ParallelMoveResolverARM::EmitMove(size_t index) {
1783  MoveOperands* move = moves_.Get(index);
1784  Location source = move->GetSource();
1785  Location destination = move->GetDestination();
1786
1787  if (source.IsRegister()) {
1788    if (destination.IsRegister()) {
1789      __ Mov(destination.As<Register>(), source.As<Register>());
1790    } else {
1791      DCHECK(destination.IsStackSlot());
1792      __ StoreToOffset(kStoreWord, source.As<Register>(),
1793                       SP, destination.GetStackIndex());
1794    }
1795  } else if (source.IsStackSlot()) {
1796    if (destination.IsRegister()) {
1797      __ LoadFromOffset(kLoadWord, destination.As<Register>(),
1798                        SP, source.GetStackIndex());
1799    } else {
1800      DCHECK(destination.IsStackSlot());
1801      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1802      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1803    }
1804  } else {
1805    DCHECK(source.IsConstant());
1806    DCHECK(source.GetConstant()->IsIntConstant());
1807    int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1808    if (destination.IsRegister()) {
1809      __ LoadImmediate(destination.As<Register>(), value);
1810    } else {
1811      DCHECK(destination.IsStackSlot());
1812      __ LoadImmediate(IP, value);
1813      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1814    }
1815  }
1816}
1817
1818void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1819  __ Mov(IP, reg);
1820  __ LoadFromOffset(kLoadWord, reg, SP, mem);
1821  __ StoreToOffset(kStoreWord, IP, SP, mem);
1822}
1823
1824void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1825  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1826  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1827  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1828                    SP, mem1 + stack_offset);
1829  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1830  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1831                   SP, mem2 + stack_offset);
1832  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1833}
1834
1835void ParallelMoveResolverARM::EmitSwap(size_t index) {
1836  MoveOperands* move = moves_.Get(index);
1837  Location source = move->GetSource();
1838  Location destination = move->GetDestination();
1839
1840  if (source.IsRegister() && destination.IsRegister()) {
1841    DCHECK_NE(source.As<Register>(), IP);
1842    DCHECK_NE(destination.As<Register>(), IP);
1843    __ Mov(IP, source.As<Register>());
1844    __ Mov(source.As<Register>(), destination.As<Register>());
1845    __ Mov(destination.As<Register>(), IP);
1846  } else if (source.IsRegister() && destination.IsStackSlot()) {
1847    Exchange(source.As<Register>(), destination.GetStackIndex());
1848  } else if (source.IsStackSlot() && destination.IsRegister()) {
1849    Exchange(destination.As<Register>(), source.GetStackIndex());
1850  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1851    Exchange(source.GetStackIndex(), destination.GetStackIndex());
1852  } else {
1853    LOG(FATAL) << "Unimplemented";
1854  }
1855}
1856
1857void ParallelMoveResolverARM::SpillScratch(int reg) {
1858  __ Push(static_cast<Register>(reg));
1859}
1860
1861void ParallelMoveResolverARM::RestoreScratch(int reg) {
1862  __ Pop(static_cast<Register>(reg));
1863}
1864
1865}  // namespace arm
1866}  // namespace art
1867