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