code_generator_arm.cc revision f12feb8e0e857f2832545b3f28d31bad5a9d3903
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 "thread.h"
24#include "utils/assembler.h"
25#include "utils/arm/assembler_arm.h"
26#include "utils/arm/managed_register_arm.h"
27#include "utils/stack_checks.h"
28
29namespace art {
30
31arm::ArmManagedRegister Location::AsArm() const {
32  return reg().AsArm();
33}
34
35namespace arm {
36
37static constexpr bool kExplicitStackOverflowCheck = false;
38
39static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2;  // LR, R6, R7
40static constexpr int kCurrentMethodStackOffset = 0;
41
42#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
43
44class NullCheckSlowPathARM : public SlowPathCode {
45 public:
46  explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
47
48  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
49    __ Bind(GetEntryLabel());
50    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
51    __ ldr(LR, Address(TR, offset));
52    __ blx(LR);
53    codegen->RecordPcInfo(dex_pc_);
54  }
55
56 private:
57  const uint32_t dex_pc_;
58  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
59};
60
61class StackOverflowCheckSlowPathARM : public SlowPathCode {
62 public:
63  StackOverflowCheckSlowPathARM() {}
64
65  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
66    __ Bind(GetEntryLabel());
67    __ LoadFromOffset(kLoadWord, PC, TR,
68        QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
69  }
70
71 private:
72  DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
73};
74
75#undef __
76#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
77
78inline Condition ARMCondition(IfCondition cond) {
79  switch (cond) {
80    case kCondEQ: return EQ;
81    case kCondNE: return NE;
82    case kCondLT: return LT;
83    case kCondLE: return LE;
84    case kCondGT: return GT;
85    case kCondGE: return GE;
86    default:
87      LOG(FATAL) << "Unknown if condition";
88  }
89  return EQ;        // Unreachable.
90}
91
92inline Condition ARMOppositeCondition(IfCondition cond) {
93  switch (cond) {
94    case kCondEQ: return NE;
95    case kCondNE: return EQ;
96    case kCondLT: return GE;
97    case kCondLE: return GT;
98    case kCondGT: return LE;
99    case kCondGE: return LT;
100    default:
101      LOG(FATAL) << "Unknown if condition";
102  }
103  return EQ;        // Unreachable.
104}
105
106void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
107  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
108}
109
110void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
111  stream << ArmManagedRegister::FromDRegister(DRegister(reg));
112}
113
114CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
115    : CodeGenerator(graph, kNumberOfRegIds),
116      location_builder_(graph, this),
117      instruction_visitor_(graph, this),
118      move_resolver_(graph->GetArena(), this),
119      assembler_(true) {}
120
121size_t CodeGeneratorARM::FrameEntrySpillSize() const {
122  return kNumberOfPushedRegistersAtEntry * kArmWordSize;
123}
124
125static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
126  return blocked_registers + kNumberOfAllocIds;
127}
128
129ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
130                                                       bool* blocked_registers) const {
131  switch (type) {
132    case Primitive::kPrimLong: {
133      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
134      size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
135      ArmManagedRegister pair =
136          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
137      blocked_registers[pair.AsRegisterPairLow()] = true;
138      blocked_registers[pair.AsRegisterPairHigh()] = true;
139       // Block all other register pairs that share a register with `pair`.
140      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
141        ArmManagedRegister current =
142            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
143        if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
144            || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
145            || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
146            || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
147          blocked_register_pairs[i] = true;
148        }
149      }
150      return pair;
151    }
152
153    case Primitive::kPrimByte:
154    case Primitive::kPrimBoolean:
155    case Primitive::kPrimChar:
156    case Primitive::kPrimShort:
157    case Primitive::kPrimInt:
158    case Primitive::kPrimNot: {
159      int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
160      // Block all register pairs that contain `reg`.
161      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
162      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
163        ArmManagedRegister current =
164            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
165        if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
166          blocked_register_pairs[i] = true;
167        }
168      }
169      return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
170    }
171
172    case Primitive::kPrimFloat:
173    case Primitive::kPrimDouble:
174      LOG(FATAL) << "Unimplemented register type " << type;
175
176    case Primitive::kPrimVoid:
177      LOG(FATAL) << "Unreachable type " << type;
178  }
179
180  return ManagedRegister::NoRegister();
181}
182
183void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
184  bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
185
186  // Don't allocate the dalvik style register pair passing.
187  blocked_register_pairs[R1_R2] = true;
188
189  // Stack register, LR and PC are always reserved.
190  blocked_registers[SP] = true;
191  blocked_registers[LR] = true;
192  blocked_registers[PC] = true;
193
194  // Reserve R4 for suspend check.
195  blocked_registers[R4] = true;
196  blocked_register_pairs[R4_R5] = true;
197
198  // Reserve thread register.
199  blocked_registers[TR] = true;
200
201  // Reserve temp register.
202  blocked_registers[IP] = true;
203
204  // TODO: We currently don't use Quick's callee saved registers.
205  // We always save and restore R6 and R7 to make sure we can use three
206  // register pairs for long operations.
207  blocked_registers[R5] = true;
208  blocked_registers[R8] = true;
209  blocked_registers[R10] = true;
210  blocked_registers[R11] = true;
211}
212
213size_t CodeGeneratorARM::GetNumberOfRegisters() const {
214  return kNumberOfRegIds;
215}
216
217static Location ArmCoreLocation(Register reg) {
218  return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
219}
220
221InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
222      : HGraphVisitor(graph),
223        assembler_(codegen->GetAssembler()),
224        codegen_(codegen) {}
225
226void CodeGeneratorARM::GenerateFrameEntry() {
227  bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kArm);
228  if (!skip_overflow_check) {
229    if (kExplicitStackOverflowCheck) {
230      SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
231      AddSlowPath(slow_path);
232
233      __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
234      __ cmp(SP, ShifterOperand(IP));
235      __ b(slow_path->GetEntryLabel(), CC);
236    } else {
237      __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
238      __ ldr(IP, Address(IP, 0));
239      RecordPcInfo(0);
240    }
241  }
242
243  core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
244  __ PushList(1 << LR | 1 << R6 | 1 << R7);
245
246  // The return PC has already been pushed on the stack.
247  __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
248  __ str(R0, Address(SP, 0));
249}
250
251void CodeGeneratorARM::GenerateFrameExit() {
252  __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
253  __ PopList(1 << PC | 1 << R6 | 1 << R7);
254}
255
256void CodeGeneratorARM::Bind(Label* label) {
257  __ Bind(label);
258}
259
260Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
261  switch (load->GetType()) {
262    case Primitive::kPrimLong:
263      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
264      break;
265
266    case Primitive::kPrimInt:
267    case Primitive::kPrimNot:
268      return Location::StackSlot(GetStackSlot(load->GetLocal()));
269
270    case Primitive::kPrimFloat:
271    case Primitive::kPrimDouble:
272      LOG(FATAL) << "Unimplemented type " << load->GetType();
273
274    case Primitive::kPrimBoolean:
275    case Primitive::kPrimByte:
276    case Primitive::kPrimChar:
277    case Primitive::kPrimShort:
278    case Primitive::kPrimVoid:
279      LOG(FATAL) << "Unexpected type " << load->GetType();
280  }
281
282  LOG(FATAL) << "Unreachable";
283  return Location();
284}
285
286Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
287  switch (type) {
288    case Primitive::kPrimBoolean:
289    case Primitive::kPrimByte:
290    case Primitive::kPrimChar:
291    case Primitive::kPrimShort:
292    case Primitive::kPrimInt:
293    case Primitive::kPrimNot: {
294      uint32_t index = gp_index_++;
295      if (index < calling_convention.GetNumberOfRegisters()) {
296        return ArmCoreLocation(calling_convention.GetRegisterAt(index));
297      } else {
298        return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
299      }
300    }
301
302    case Primitive::kPrimLong: {
303      uint32_t index = gp_index_;
304      gp_index_ += 2;
305      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
306        return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
307            calling_convention.GetRegisterPairAt(index)));
308      } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
309        return Location::QuickParameter(index);
310      } else {
311        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
312      }
313    }
314
315    case Primitive::kPrimDouble:
316    case Primitive::kPrimFloat:
317      LOG(FATAL) << "Unimplemented parameter type " << type;
318      break;
319
320    case Primitive::kPrimVoid:
321      LOG(FATAL) << "Unexpected parameter type " << type;
322      break;
323  }
324  return Location();
325}
326
327void CodeGeneratorARM::Move32(Location destination, Location source) {
328  if (source.Equals(destination)) {
329    return;
330  }
331  if (destination.IsRegister()) {
332    if (source.IsRegister()) {
333      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
334    } else {
335      __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
336    }
337  } else {
338    DCHECK(destination.IsStackSlot());
339    if (source.IsRegister()) {
340      __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
341    } else {
342      __ ldr(IP, Address(SP, source.GetStackIndex()));
343      __ str(IP, Address(SP, destination.GetStackIndex()));
344    }
345  }
346}
347
348void CodeGeneratorARM::Move64(Location destination, Location source) {
349  if (source.Equals(destination)) {
350    return;
351  }
352  if (destination.IsRegister()) {
353    if (source.IsRegister()) {
354      __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
355      __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
356    } else if (source.IsQuickParameter()) {
357      uint32_t argument_index = source.GetQuickParameterIndex();
358      InvokeDexCallingConvention calling_convention;
359      __ Mov(destination.AsArm().AsRegisterPairLow(),
360             calling_convention.GetRegisterAt(argument_index));
361      __ ldr(destination.AsArm().AsRegisterPairHigh(),
362             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
363    } else {
364      DCHECK(source.IsDoubleStackSlot());
365      if (destination.AsArm().AsRegisterPair() == R1_R2) {
366        __ ldr(R1, Address(SP, source.GetStackIndex()));
367        __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
368      } else {
369        __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
370                          SP, source.GetStackIndex());
371      }
372    }
373  } else if (destination.IsQuickParameter()) {
374    InvokeDexCallingConvention calling_convention;
375    uint32_t argument_index = destination.GetQuickParameterIndex();
376    if (source.IsRegister()) {
377      __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
378      __ str(source.AsArm().AsRegisterPairHigh(),
379             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
380    } else {
381      DCHECK(source.IsDoubleStackSlot());
382      __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
383      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
384      __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
385    }
386  } else {
387    DCHECK(destination.IsDoubleStackSlot());
388    if (source.IsRegister()) {
389      if (source.AsArm().AsRegisterPair() == R1_R2) {
390        __ str(R1, Address(SP, destination.GetStackIndex()));
391        __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
392      } else {
393        __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
394                         SP, destination.GetStackIndex());
395      }
396    } else if (source.IsQuickParameter()) {
397      InvokeDexCallingConvention calling_convention;
398      uint32_t argument_index = source.GetQuickParameterIndex();
399      __ str(calling_convention.GetRegisterAt(argument_index),
400             Address(SP, destination.GetStackIndex()));
401      __ ldr(R0,
402             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
403      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
404    } else {
405      DCHECK(source.IsDoubleStackSlot());
406      __ ldr(IP, Address(SP, source.GetStackIndex()));
407      __ str(IP, Address(SP, destination.GetStackIndex()));
408      __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
409      __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
410    }
411  }
412}
413
414void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
415  LocationSummary* locations = instruction->GetLocations();
416  if (locations != nullptr && locations->Out().Equals(location)) {
417    return;
418  }
419
420  if (instruction->AsIntConstant() != nullptr) {
421    int32_t value = instruction->AsIntConstant()->GetValue();
422    if (location.IsRegister()) {
423      __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
424    } else {
425      DCHECK(location.IsStackSlot());
426      __ LoadImmediate(IP, value);
427      __ str(IP, Address(SP, location.GetStackIndex()));
428    }
429  } else if (instruction->AsLongConstant() != nullptr) {
430    int64_t value = instruction->AsLongConstant()->GetValue();
431    if (location.IsRegister()) {
432      __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
433      __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
434    } else {
435      DCHECK(location.IsDoubleStackSlot());
436      __ LoadImmediate(IP, Low32Bits(value));
437      __ str(IP, Address(SP, location.GetStackIndex()));
438      __ LoadImmediate(IP, High32Bits(value));
439      __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
440    }
441  } else if (instruction->AsLoadLocal() != nullptr) {
442    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
443    switch (instruction->GetType()) {
444      case Primitive::kPrimBoolean:
445      case Primitive::kPrimByte:
446      case Primitive::kPrimChar:
447      case Primitive::kPrimShort:
448      case Primitive::kPrimInt:
449      case Primitive::kPrimNot:
450        Move32(location, Location::StackSlot(stack_slot));
451        break;
452
453      case Primitive::kPrimLong:
454        Move64(location, Location::DoubleStackSlot(stack_slot));
455        break;
456
457      default:
458        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
459    }
460  } else {
461    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
462    switch (instruction->GetType()) {
463      case Primitive::kPrimBoolean:
464      case Primitive::kPrimByte:
465      case Primitive::kPrimChar:
466      case Primitive::kPrimShort:
467      case Primitive::kPrimNot:
468      case Primitive::kPrimInt:
469        Move32(location, locations->Out());
470        break;
471
472      case Primitive::kPrimLong:
473        Move64(location, locations->Out());
474        break;
475
476      default:
477        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
478    }
479  }
480}
481
482void LocationsBuilderARM::VisitGoto(HGoto* got) {
483  got->SetLocations(nullptr);
484}
485
486void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
487  HBasicBlock* successor = got->GetSuccessor();
488  if (GetGraph()->GetExitBlock() == successor) {
489    codegen_->GenerateFrameExit();
490  } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
491    __ b(codegen_->GetLabelOf(successor));
492  }
493}
494
495void LocationsBuilderARM::VisitExit(HExit* exit) {
496  exit->SetLocations(nullptr);
497}
498
499void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
500  if (kIsDebugBuild) {
501    __ Comment("Unreachable");
502    __ bkpt(0);
503  }
504}
505
506void LocationsBuilderARM::VisitIf(HIf* if_instr) {
507  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
508  HInstruction* cond = if_instr->InputAt(0);
509  DCHECK(cond->IsCondition());
510  HCondition* condition = cond->AsCondition();
511  if (condition->NeedsMaterialization()) {
512    locations->SetInAt(0, Location::Any());
513  }
514  if_instr->SetLocations(locations);
515}
516
517void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
518  HInstruction* cond = if_instr->InputAt(0);
519  DCHECK(cond->IsCondition());
520  HCondition* condition = cond->AsCondition();
521  if (condition->NeedsMaterialization()) {
522    // Condition has been materialized, compare the output to 0
523    DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
524    __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
525           ShifterOperand(0));
526    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
527  } else {
528    // Condition has not been materialized, use its inputs as the comparison and its
529    // condition as the branch condition.
530    LocationSummary* locations = condition->GetLocations();
531    if (locations->InAt(1).IsRegister()) {
532      __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
533             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
534    } else {
535      DCHECK(locations->InAt(1).IsConstant());
536      int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
537      ShifterOperand operand;
538      if (ShifterOperand::CanHoldArm(value, &operand)) {
539        __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
540      } else {
541        Register temp = IP;
542        __ LoadImmediate(temp, value);
543        __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
544      }
545    }
546    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
547         ARMCondition(condition->GetCondition()));
548  }
549
550  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
551    __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
552  }
553}
554
555
556void LocationsBuilderARM::VisitCondition(HCondition* comp) {
557  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
558  locations->SetInAt(0, Location::RequiresRegister());
559  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
560  if (comp->NeedsMaterialization()) {
561    locations->SetOut(Location::RequiresRegister());
562  }
563  comp->SetLocations(locations);
564}
565
566void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
567  if (!comp->NeedsMaterialization()) return;
568
569  LocationSummary* locations = comp->GetLocations();
570  if (locations->InAt(1).IsRegister()) {
571    __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
572           ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
573  } else {
574    DCHECK(locations->InAt(1).IsConstant());
575    int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
576    ShifterOperand operand;
577    if (ShifterOperand::CanHoldArm(value, &operand)) {
578      __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
579    } else {
580      Register temp = IP;
581      __ LoadImmediate(temp, value);
582      __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
583    }
584  }
585  __ it(ARMCondition(comp->GetCondition()), kItElse);
586  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
587         ARMCondition(comp->GetCondition()));
588  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
589         ARMOppositeCondition(comp->GetCondition()));
590}
591
592void LocationsBuilderARM::VisitEqual(HEqual* comp) {
593  VisitCondition(comp);
594}
595
596void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
597  VisitCondition(comp);
598}
599
600void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
601  VisitCondition(comp);
602}
603
604void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
605  VisitCondition(comp);
606}
607
608void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
609  VisitCondition(comp);
610}
611
612void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
613  VisitCondition(comp);
614}
615
616void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
617  VisitCondition(comp);
618}
619
620void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
621  VisitCondition(comp);
622}
623
624void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
625  VisitCondition(comp);
626}
627
628void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
629  VisitCondition(comp);
630}
631
632void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
633  VisitCondition(comp);
634}
635
636void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
637  VisitCondition(comp);
638}
639
640void LocationsBuilderARM::VisitLocal(HLocal* local) {
641  local->SetLocations(nullptr);
642}
643
644void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
645  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
646}
647
648void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
649  load->SetLocations(nullptr);
650}
651
652void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
653  // Nothing to do, this is driven by the code generator.
654}
655
656void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
657  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
658  switch (store->InputAt(1)->GetType()) {
659    case Primitive::kPrimBoolean:
660    case Primitive::kPrimByte:
661    case Primitive::kPrimChar:
662    case Primitive::kPrimShort:
663    case Primitive::kPrimInt:
664    case Primitive::kPrimNot:
665      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
666      break;
667
668    case Primitive::kPrimLong:
669      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
670      break;
671
672    default:
673      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
674  }
675  store->SetLocations(locations);
676}
677
678void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
679}
680
681void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
682  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
683  locations->SetOut(Location::ConstantLocation(constant));
684  constant->SetLocations(locations);
685}
686
687void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
688}
689
690void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
691  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
692  locations->SetOut(Location::ConstantLocation(constant));
693  constant->SetLocations(locations);
694}
695
696void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
697  // Will be generated at use site.
698}
699
700void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
701  ret->SetLocations(nullptr);
702}
703
704void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
705  codegen_->GenerateFrameExit();
706}
707
708void LocationsBuilderARM::VisitReturn(HReturn* ret) {
709  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
710  switch (ret->InputAt(0)->GetType()) {
711    case Primitive::kPrimBoolean:
712    case Primitive::kPrimByte:
713    case Primitive::kPrimChar:
714    case Primitive::kPrimShort:
715    case Primitive::kPrimInt:
716    case Primitive::kPrimNot:
717      locations->SetInAt(0, ArmCoreLocation(R0));
718      break;
719
720    case Primitive::kPrimLong:
721      locations->SetInAt(
722          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
723      break;
724
725    default:
726      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
727  }
728
729  ret->SetLocations(locations);
730}
731
732void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
733  if (kIsDebugBuild) {
734    switch (ret->InputAt(0)->GetType()) {
735      case Primitive::kPrimBoolean:
736      case Primitive::kPrimByte:
737      case Primitive::kPrimChar:
738      case Primitive::kPrimShort:
739      case Primitive::kPrimInt:
740      case Primitive::kPrimNot:
741        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
742        break;
743
744      case Primitive::kPrimLong:
745        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
746        break;
747
748      default:
749        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
750    }
751  }
752  codegen_->GenerateFrameExit();
753}
754
755void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
756  codegen_->MarkNotLeaf();
757  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
758  locations->AddTemp(ArmCoreLocation(R0));
759
760  InvokeDexCallingConventionVisitor calling_convention_visitor;
761  for (size_t i = 0; i < invoke->InputCount(); i++) {
762    HInstruction* input = invoke->InputAt(i);
763    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
764  }
765
766  switch (invoke->GetType()) {
767    case Primitive::kPrimBoolean:
768    case Primitive::kPrimByte:
769    case Primitive::kPrimChar:
770    case Primitive::kPrimShort:
771    case Primitive::kPrimInt:
772    case Primitive::kPrimNot:
773      locations->SetOut(ArmCoreLocation(R0));
774      break;
775
776    case Primitive::kPrimLong:
777      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
778      break;
779
780    case Primitive::kPrimVoid:
781      break;
782
783    case Primitive::kPrimDouble:
784    case Primitive::kPrimFloat:
785      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
786      break;
787  }
788
789  invoke->SetLocations(locations);
790}
791
792void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
793  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
794}
795
796void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
797  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
798  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
799  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
800      invoke->GetIndexInDexCache() * kArmWordSize;
801
802  // TODO: Implement all kinds of calls:
803  // 1) boot -> boot
804  // 2) app -> boot
805  // 3) app -> app
806  //
807  // Currently we implement the app -> app logic, which looks up in the resolve cache.
808
809  // temp = method;
810  LoadCurrentMethod(temp);
811  // temp = temp->dex_cache_resolved_methods_;
812  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
813  // temp = temp[index_in_cache]
814  __ ldr(temp, Address(temp, index_in_cache));
815  // LR = temp[offset_of_quick_compiled_code]
816  __ ldr(LR, Address(temp,
817                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
818  // LR()
819  __ blx(LR);
820
821  codegen_->RecordPcInfo(invoke->GetDexPc());
822  DCHECK(!codegen_->IsLeafMethod());
823}
824
825void LocationsBuilderARM::VisitAdd(HAdd* add) {
826  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
827  switch (add->GetResultType()) {
828    case Primitive::kPrimInt:
829    case Primitive::kPrimLong: {
830      locations->SetInAt(0, Location::RequiresRegister());
831      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
832      locations->SetOut(Location::RequiresRegister());
833      break;
834    }
835
836    case Primitive::kPrimBoolean:
837    case Primitive::kPrimByte:
838    case Primitive::kPrimChar:
839    case Primitive::kPrimShort:
840      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
841      break;
842
843    default:
844      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
845  }
846  add->SetLocations(locations);
847}
848
849void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
850  LocationSummary* locations = add->GetLocations();
851  switch (add->GetResultType()) {
852    case Primitive::kPrimInt:
853      if (locations->InAt(1).IsRegister()) {
854        __ add(locations->Out().AsArm().AsCoreRegister(),
855               locations->InAt(0).AsArm().AsCoreRegister(),
856               ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
857      } else {
858        __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
859                       locations->InAt(0).AsArm().AsCoreRegister(),
860                       locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
861      }
862      break;
863
864    case Primitive::kPrimLong:
865      __ adds(locations->Out().AsArm().AsRegisterPairLow(),
866              locations->InAt(0).AsArm().AsRegisterPairLow(),
867              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
868      __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
869             locations->InAt(0).AsArm().AsRegisterPairHigh(),
870             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
871      break;
872
873    case Primitive::kPrimBoolean:
874    case Primitive::kPrimByte:
875    case Primitive::kPrimChar:
876    case Primitive::kPrimShort:
877      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
878      break;
879
880    default:
881      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
882  }
883}
884
885void LocationsBuilderARM::VisitSub(HSub* sub) {
886  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
887  switch (sub->GetResultType()) {
888    case Primitive::kPrimInt:
889    case Primitive::kPrimLong: {
890      locations->SetInAt(0, Location::RequiresRegister());
891      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
892      locations->SetOut(Location::RequiresRegister());
893      break;
894    }
895
896    case Primitive::kPrimBoolean:
897    case Primitive::kPrimByte:
898    case Primitive::kPrimChar:
899    case Primitive::kPrimShort:
900      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
901      break;
902
903    default:
904      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
905  }
906  sub->SetLocations(locations);
907}
908
909void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
910  LocationSummary* locations = sub->GetLocations();
911  switch (sub->GetResultType()) {
912    case Primitive::kPrimInt: {
913      if (locations->InAt(1).IsRegister()) {
914        __ sub(locations->Out().AsArm().AsCoreRegister(),
915               locations->InAt(0).AsArm().AsCoreRegister(),
916               ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
917      } else {
918        __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
919                       locations->InAt(0).AsArm().AsCoreRegister(),
920                       -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
921      }
922      break;
923    }
924
925    case Primitive::kPrimLong:
926      __ subs(locations->Out().AsArm().AsRegisterPairLow(),
927              locations->InAt(0).AsArm().AsRegisterPairLow(),
928              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
929      __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
930             locations->InAt(0).AsArm().AsRegisterPairHigh(),
931             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
932      break;
933
934    case Primitive::kPrimBoolean:
935    case Primitive::kPrimByte:
936    case Primitive::kPrimChar:
937    case Primitive::kPrimShort:
938      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
939      break;
940
941    default:
942      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
943  }
944}
945
946static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
947static constexpr size_t kRuntimeParameterCoreRegistersLength =
948    arraysize(kRuntimeParameterCoreRegisters);
949
950class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
951 public:
952  InvokeRuntimeCallingConvention()
953      : CallingConvention(kRuntimeParameterCoreRegisters,
954                          kRuntimeParameterCoreRegistersLength) {}
955
956 private:
957  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
958};
959
960void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
961  codegen_->MarkNotLeaf();
962  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
963  InvokeRuntimeCallingConvention calling_convention;
964  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
965  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
966  locations->SetOut(ArmCoreLocation(R0));
967  instruction->SetLocations(locations);
968}
969
970void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
971  InvokeRuntimeCallingConvention calling_convention;
972  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
973  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
974
975  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
976  __ ldr(LR, Address(TR, offset));
977  __ blx(LR);
978
979  codegen_->RecordPcInfo(instruction->GetDexPc());
980  DCHECK(!codegen_->IsLeafMethod());
981}
982
983void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
984  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
985  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
986  if (location.IsStackSlot()) {
987    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
988  } else if (location.IsDoubleStackSlot()) {
989    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
990  }
991  locations->SetOut(location);
992  instruction->SetLocations(locations);
993}
994
995void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
996  // Nothing to do, the parameter is already at its location.
997}
998
999void LocationsBuilderARM::VisitNot(HNot* instruction) {
1000  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1001  locations->SetInAt(0, Location::RequiresRegister());
1002  locations->SetOut(Location::RequiresRegister());
1003  instruction->SetLocations(locations);
1004}
1005
1006void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1007  LocationSummary* locations = instruction->GetLocations();
1008  __ eor(locations->Out().AsArm().AsCoreRegister(),
1009         locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
1010}
1011
1012void LocationsBuilderARM::VisitCompare(HCompare* compare) {
1013  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
1014  locations->SetInAt(0, Location::RequiresRegister());
1015  locations->SetInAt(1, Location::RequiresRegister());
1016  locations->SetOut(Location::RequiresRegister());
1017  compare->SetLocations(locations);
1018}
1019
1020void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1021  Label greater, done;
1022  LocationSummary* locations = compare->GetLocations();
1023  switch (compare->InputAt(0)->GetType()) {
1024    case Primitive::kPrimLong: {
1025      Register output = locations->Out().AsArm().AsCoreRegister();
1026      ArmManagedRegister left = locations->InAt(0).AsArm();
1027      ArmManagedRegister right = locations->InAt(1).AsArm();
1028      Label less, greater, done;
1029      __ cmp(left.AsRegisterPairHigh(),
1030             ShifterOperand(right.AsRegisterPairHigh()));  // Signed compare.
1031      __ b(&less, LT);
1032      __ b(&greater, GT);
1033      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1034      // the status flags.
1035      __ LoadImmediate(output, 0);
1036      __ cmp(left.AsRegisterPairLow(),
1037             ShifterOperand(right.AsRegisterPairLow()));  // Unsigned compare.
1038      __ b(&done, EQ);
1039      __ b(&less, CC);
1040
1041      __ Bind(&greater);
1042      __ LoadImmediate(output, 1);
1043      __ b(&done);
1044
1045      __ Bind(&less);
1046      __ LoadImmediate(output, -1);
1047
1048      __ Bind(&done);
1049      break;
1050    }
1051    default:
1052      LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1053  }
1054}
1055
1056void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
1057  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1058  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1059    locations->SetInAt(i, Location::Any());
1060  }
1061  locations->SetOut(Location::Any());
1062  instruction->SetLocations(locations);
1063}
1064
1065void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
1066  LOG(FATAL) << "Unreachable";
1067}
1068
1069void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1070  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1071  locations->SetInAt(0, Location::RequiresRegister());
1072  locations->SetInAt(1, Location::RequiresRegister());
1073  // Temporary registers for the write barrier.
1074  if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
1075    locations->AddTemp(Location::RequiresRegister());
1076    locations->AddTemp(Location::RequiresRegister());
1077  }
1078  instruction->SetLocations(locations);
1079}
1080
1081void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1082  LocationSummary* locations = instruction->GetLocations();
1083  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1084  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1085  Primitive::Type field_type = instruction->InputAt(1)->GetType();
1086
1087  switch (field_type) {
1088    case Primitive::kPrimBoolean:
1089    case Primitive::kPrimByte: {
1090      Register value = locations->InAt(1).AsArm().AsCoreRegister();
1091      __ StoreToOffset(kStoreByte, value, obj, offset);
1092      break;
1093    }
1094
1095    case Primitive::kPrimShort:
1096    case Primitive::kPrimChar: {
1097      Register value = locations->InAt(1).AsArm().AsCoreRegister();
1098      __ StoreToOffset(kStoreHalfword, value, obj, offset);
1099      break;
1100    }
1101
1102    case Primitive::kPrimInt: {
1103      Register value = locations->InAt(1).AsArm().AsCoreRegister();
1104      __ StoreToOffset(kStoreWord, value, obj, offset);
1105      break;
1106    }
1107
1108    case Primitive::kPrimNot: {
1109      Register value = locations->InAt(1).AsArm().AsCoreRegister();
1110      __ StoreToOffset(kStoreWord, value, obj, offset);
1111
1112      Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1113      Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1114      Label is_null;
1115      __ CompareAndBranchIfZero(value, &is_null);
1116      __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1117      __ Lsr(temp, obj, gc::accounting::CardTable::kCardShift);
1118      __ strb(card, Address(card, temp));
1119      __ Bind(&is_null);
1120      break;
1121    }
1122
1123    case Primitive::kPrimLong: {
1124      ArmManagedRegister value = locations->InAt(1).AsArm();
1125      __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1126      break;
1127    }
1128
1129    case Primitive::kPrimFloat:
1130    case Primitive::kPrimDouble:
1131      LOG(FATAL) << "Unimplemented register type " << field_type;
1132
1133    case Primitive::kPrimVoid:
1134      LOG(FATAL) << "Unreachable type " << field_type;
1135  }
1136}
1137
1138void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1139  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1140  locations->SetInAt(0, Location::RequiresRegister());
1141  locations->SetOut(Location::RequiresRegister());
1142  instruction->SetLocations(locations);
1143}
1144
1145void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1146  LocationSummary* locations = instruction->GetLocations();
1147  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1148  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1149
1150  switch (instruction->GetType()) {
1151    case Primitive::kPrimBoolean: {
1152      Register out = locations->Out().AsArm().AsCoreRegister();
1153      __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1154      break;
1155    }
1156
1157    case Primitive::kPrimByte: {
1158      Register out = locations->Out().AsArm().AsCoreRegister();
1159      __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1160      break;
1161    }
1162
1163    case Primitive::kPrimShort: {
1164      Register out = locations->Out().AsArm().AsCoreRegister();
1165      __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1166      break;
1167    }
1168
1169    case Primitive::kPrimChar: {
1170      Register out = locations->Out().AsArm().AsCoreRegister();
1171      __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1172      break;
1173    }
1174
1175    case Primitive::kPrimInt:
1176    case Primitive::kPrimNot: {
1177      Register out = locations->Out().AsArm().AsCoreRegister();
1178      __ LoadFromOffset(kLoadWord, out, obj, offset);
1179      break;
1180    }
1181
1182    case Primitive::kPrimLong: {
1183      // TODO: support volatile.
1184      ArmManagedRegister out = locations->Out().AsArm();
1185      __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1186      break;
1187    }
1188
1189    case Primitive::kPrimFloat:
1190    case Primitive::kPrimDouble:
1191      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1192
1193    case Primitive::kPrimVoid:
1194      LOG(FATAL) << "Unreachable type " << instruction->GetType();
1195  }
1196}
1197
1198void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1199  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1200  locations->SetInAt(0, Location::RequiresRegister());
1201  // TODO: Have a normalization phase that makes this instruction never used.
1202  locations->SetOut(Location::SameAsFirstInput());
1203  instruction->SetLocations(locations);
1204}
1205
1206void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1207  SlowPathCode* slow_path =
1208      new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1209  codegen_->AddSlowPath(slow_path);
1210
1211  LocationSummary* locations = instruction->GetLocations();
1212  Location obj = locations->InAt(0);
1213  DCHECK(obj.Equals(locations->Out()));
1214
1215  if (obj.IsRegister()) {
1216    __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1217  }
1218  __ b(slow_path->GetEntryLabel(), EQ);
1219}
1220
1221void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1222  temp->SetLocations(nullptr);
1223}
1224
1225void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1226  // Nothing to do, this is driven by the code generator.
1227}
1228
1229void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
1230  LOG(FATAL) << "Unreachable";
1231}
1232
1233void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
1234  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1235}
1236
1237ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1238  return codegen_->GetAssembler();
1239}
1240
1241void ParallelMoveResolverARM::EmitMove(size_t index) {
1242  MoveOperands* move = moves_.Get(index);
1243  Location source = move->GetSource();
1244  Location destination = move->GetDestination();
1245
1246  if (source.IsRegister()) {
1247    if (destination.IsRegister()) {
1248      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1249    } else {
1250      DCHECK(destination.IsStackSlot());
1251      __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1252                       SP, destination.GetStackIndex());
1253    }
1254  } else if (source.IsStackSlot()) {
1255    if (destination.IsRegister()) {
1256      __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1257                        SP, source.GetStackIndex());
1258    } else {
1259      DCHECK(destination.IsStackSlot());
1260      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1261      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1262    }
1263  } else {
1264    DCHECK(source.IsConstant());
1265    DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1266    int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1267    if (destination.IsRegister()) {
1268      __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1269    } else {
1270      DCHECK(destination.IsStackSlot());
1271      __ LoadImmediate(IP, value);
1272      __ str(IP, Address(SP, destination.GetStackIndex()));
1273    }
1274  }
1275}
1276
1277void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1278  __ Mov(IP, reg);
1279  __ LoadFromOffset(kLoadWord, reg, SP, mem);
1280  __ StoreToOffset(kStoreWord, IP, SP, mem);
1281}
1282
1283void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1284  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1285  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1286  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1287                    SP, mem1 + stack_offset);
1288  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1289  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1290                   SP, mem2 + stack_offset);
1291  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1292}
1293
1294void ParallelMoveResolverARM::EmitSwap(size_t index) {
1295  MoveOperands* move = moves_.Get(index);
1296  Location source = move->GetSource();
1297  Location destination = move->GetDestination();
1298
1299  if (source.IsRegister() && destination.IsRegister()) {
1300    DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1301    DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1302    __ Mov(IP, source.AsArm().AsCoreRegister());
1303    __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1304    __ Mov(destination.AsArm().AsCoreRegister(), IP);
1305  } else if (source.IsRegister() && destination.IsStackSlot()) {
1306    Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1307  } else if (source.IsStackSlot() && destination.IsRegister()) {
1308    Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1309  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1310    Exchange(source.GetStackIndex(), destination.GetStackIndex());
1311  } else {
1312    LOG(FATAL) << "Unimplemented";
1313  }
1314}
1315
1316void ParallelMoveResolverARM::SpillScratch(int reg) {
1317  __ Push(static_cast<Register>(reg));
1318}
1319
1320void ParallelMoveResolverARM::RestoreScratch(int reg) {
1321  __ Pop(static_cast<Register>(reg));
1322}
1323
1324}  // namespace arm
1325}  // namespace art
1326