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