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