code_generator_arm.cc revision 20dfc797dc631bf8d655dcf123f46f13332d3074
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
27#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
28
29namespace art {
30
31arm::ArmManagedRegister Location::AsArm() const {
32  return reg().AsArm();
33}
34
35namespace arm {
36
37
38inline Condition ARMCondition(IfCondition cond) {
39  switch (cond) {
40    case kCondEQ: return EQ;
41    case kCondNE: return NE;
42    case kCondLT: return LT;
43    case kCondLE: return LE;
44    case kCondGT: return GT;
45    case kCondGE: return GE;
46    default:
47      LOG(FATAL) << "Unknown if condition";
48  }
49  return EQ;        // Unreachable.
50}
51
52inline Condition ARMOppositeCondition(IfCondition cond) {
53  switch (cond) {
54    case kCondEQ: return NE;
55    case kCondNE: return EQ;
56    case kCondLT: return GE;
57    case kCondLE: return GT;
58    case kCondGT: return LE;
59    case kCondGE: return LT;
60    default:
61      LOG(FATAL) << "Unknown if condition";
62  }
63  return EQ;        // Unreachable.
64}
65
66static constexpr int kNumberOfPushedRegistersAtEntry = 1;
67static constexpr int kCurrentMethodStackOffset = 0;
68
69void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
70  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
71}
72
73void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
74  stream << ArmManagedRegister::FromDRegister(DRegister(reg));
75}
76
77CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
78    : CodeGenerator(graph, kNumberOfRegIds),
79      location_builder_(graph, this),
80      instruction_visitor_(graph, this),
81      move_resolver_(graph->GetArena(), this) {}
82
83static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
84  return blocked_registers + kNumberOfAllocIds;
85}
86
87ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
88                                                       bool* blocked_registers) const {
89  switch (type) {
90    case Primitive::kPrimLong: {
91      size_t reg = AllocateFreeRegisterInternal(
92          GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
93      ArmManagedRegister pair =
94          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
95      blocked_registers[pair.AsRegisterPairLow()] = true;
96      blocked_registers[pair.AsRegisterPairHigh()] = true;
97      return pair;
98    }
99
100    case Primitive::kPrimByte:
101    case Primitive::kPrimBoolean:
102    case Primitive::kPrimChar:
103    case Primitive::kPrimShort:
104    case Primitive::kPrimInt:
105    case Primitive::kPrimNot: {
106      size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
107      return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
108    }
109
110    case Primitive::kPrimFloat:
111    case Primitive::kPrimDouble:
112      LOG(FATAL) << "Unimplemented register type " << type;
113
114    case Primitive::kPrimVoid:
115      LOG(FATAL) << "Unreachable type " << type;
116  }
117
118  return ManagedRegister::NoRegister();
119}
120
121void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
122  bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
123
124  // Don't allocate the dalvik style register pair passing.
125  blocked_register_pairs[R1_R2] = true;
126
127  // Stack register, LR and PC are always reserved.
128  blocked_registers[SP] = true;
129  blocked_registers[LR] = true;
130  blocked_registers[PC] = true;
131
132  // Reserve R4 for suspend check.
133  blocked_registers[R4] = true;
134  blocked_register_pairs[R4_R5] = true;
135
136  // Reserve thread register.
137  blocked_registers[TR] = true;
138
139  // Reserve temp register.
140  blocked_registers[IP] = true;
141
142  // TODO: We currently don't use Quick's callee saved registers.
143  blocked_registers[R5] = true;
144  blocked_registers[R6] = true;
145  blocked_registers[R7] = true;
146  blocked_registers[R8] = true;
147  blocked_registers[R10] = true;
148  blocked_registers[R11] = true;
149  blocked_register_pairs[R6_R7] = true;
150}
151
152size_t CodeGeneratorARM::GetNumberOfRegisters() const {
153  return kNumberOfRegIds;
154}
155
156static Location ArmCoreLocation(Register reg) {
157  return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
158}
159
160InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
161      : HGraphVisitor(graph),
162        assembler_(codegen->GetAssembler()),
163        codegen_(codegen) {}
164
165void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) {
166  SetFrameSize(RoundUp(
167      number_of_spill_slots * kVRegSize
168      + kVRegSize  // Art method
169      + kNumberOfPushedRegistersAtEntry * kArmWordSize,
170      kStackAlignment));
171}
172
173void CodeGeneratorARM::GenerateFrameEntry() {
174  core_spill_mask_ |= (1 << LR);
175  __ PushList((1 << LR));
176
177  // The return PC has already been pushed on the stack.
178  __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
179  __ str(R0, Address(SP, 0));
180}
181
182void CodeGeneratorARM::GenerateFrameExit() {
183  __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
184  __ PopList((1 << PC));
185}
186
187void CodeGeneratorARM::Bind(Label* label) {
188  __ Bind(label);
189}
190
191int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
192  uint16_t reg_number = local->GetRegNumber();
193  uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
194  uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
195  if (reg_number >= number_of_vregs - number_of_in_vregs) {
196    // Local is a parameter of the method. It is stored in the caller's frame.
197    return GetFrameSize() + kVRegSize  // ART method
198                          + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
199  } else {
200    // Local is a temporary in this method. It is stored in this method's frame.
201    return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
202                          - kVRegSize  // filler.
203                          - (number_of_vregs * kVRegSize)
204                          + (reg_number * kVRegSize);
205  }
206}
207
208Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
209  switch (load->GetType()) {
210    case Primitive::kPrimLong:
211      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
212      break;
213
214    case Primitive::kPrimInt:
215    case Primitive::kPrimNot:
216      return Location::StackSlot(GetStackSlot(load->GetLocal()));
217
218    case Primitive::kPrimFloat:
219    case Primitive::kPrimDouble:
220      LOG(FATAL) << "Unimplemented type " << load->GetType();
221
222    case Primitive::kPrimBoolean:
223    case Primitive::kPrimByte:
224    case Primitive::kPrimChar:
225    case Primitive::kPrimShort:
226    case Primitive::kPrimVoid:
227      LOG(FATAL) << "Unexpected type " << load->GetType();
228  }
229
230  LOG(FATAL) << "Unreachable";
231  return Location();
232}
233
234Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
235  switch (type) {
236    case Primitive::kPrimBoolean:
237    case Primitive::kPrimByte:
238    case Primitive::kPrimChar:
239    case Primitive::kPrimShort:
240    case Primitive::kPrimInt:
241    case Primitive::kPrimNot: {
242      uint32_t index = gp_index_++;
243      if (index < calling_convention.GetNumberOfRegisters()) {
244        return ArmCoreLocation(calling_convention.GetRegisterAt(index));
245      } else {
246        return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
247      }
248    }
249
250    case Primitive::kPrimLong: {
251      uint32_t index = gp_index_;
252      gp_index_ += 2;
253      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
254        return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
255            calling_convention.GetRegisterPairAt(index)));
256      } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
257        return Location::QuickParameter(index);
258      } else {
259        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
260      }
261    }
262
263    case Primitive::kPrimDouble:
264    case Primitive::kPrimFloat:
265      LOG(FATAL) << "Unimplemented parameter type " << type;
266      break;
267
268    case Primitive::kPrimVoid:
269      LOG(FATAL) << "Unexpected parameter type " << type;
270      break;
271  }
272  return Location();
273}
274
275void CodeGeneratorARM::Move32(Location destination, Location source) {
276  if (source.Equals(destination)) {
277    return;
278  }
279  if (destination.IsRegister()) {
280    if (source.IsRegister()) {
281      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
282    } else {
283      __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
284    }
285  } else {
286    DCHECK(destination.IsStackSlot());
287    if (source.IsRegister()) {
288      __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
289    } else {
290      __ ldr(IP, Address(SP, source.GetStackIndex()));
291      __ str(IP, Address(SP, destination.GetStackIndex()));
292    }
293  }
294}
295
296void CodeGeneratorARM::Move64(Location destination, Location source) {
297  if (source.Equals(destination)) {
298    return;
299  }
300  if (destination.IsRegister()) {
301    if (source.IsRegister()) {
302      __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
303      __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
304    } else if (source.IsQuickParameter()) {
305      uint32_t argument_index = source.GetQuickParameterIndex();
306      InvokeDexCallingConvention calling_convention;
307      __ Mov(destination.AsArm().AsRegisterPairLow(),
308             calling_convention.GetRegisterAt(argument_index));
309      __ ldr(destination.AsArm().AsRegisterPairHigh(),
310             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
311    } else {
312      DCHECK(source.IsDoubleStackSlot());
313      if (destination.AsArm().AsRegisterPair() == R1_R2) {
314        __ ldr(R1, Address(SP, source.GetStackIndex()));
315        __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
316      } else {
317        __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
318                          SP, source.GetStackIndex());
319      }
320    }
321  } else if (destination.IsQuickParameter()) {
322    InvokeDexCallingConvention calling_convention;
323    uint32_t argument_index = destination.GetQuickParameterIndex();
324    if (source.IsRegister()) {
325      __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
326      __ str(source.AsArm().AsRegisterPairHigh(),
327             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
328    } else {
329      DCHECK(source.IsDoubleStackSlot());
330      __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
331      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
332      __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
333    }
334  } else {
335    DCHECK(destination.IsDoubleStackSlot());
336    if (source.IsRegister()) {
337      if (source.AsArm().AsRegisterPair() == R1_R2) {
338        __ str(R1, Address(SP, destination.GetStackIndex()));
339        __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
340      } else {
341        __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
342                         SP, destination.GetStackIndex());
343      }
344    } else if (source.IsQuickParameter()) {
345      InvokeDexCallingConvention calling_convention;
346      uint32_t argument_index = source.GetQuickParameterIndex();
347      __ str(calling_convention.GetRegisterAt(argument_index),
348             Address(SP, destination.GetStackIndex()));
349      __ ldr(R0,
350             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
351      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
352    } else {
353      DCHECK(source.IsDoubleStackSlot());
354      __ ldr(IP, Address(SP, source.GetStackIndex()));
355      __ str(IP, Address(SP, destination.GetStackIndex()));
356      __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
357      __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
358    }
359  }
360}
361
362void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
363  if (instruction->AsIntConstant() != nullptr) {
364    int32_t value = instruction->AsIntConstant()->GetValue();
365    if (location.IsRegister()) {
366      __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
367    } else {
368      __ LoadImmediate(IP, value);
369      __ str(IP, Address(SP, location.GetStackIndex()));
370    }
371  } else if (instruction->AsLongConstant() != nullptr) {
372    int64_t value = instruction->AsLongConstant()->GetValue();
373    if (location.IsRegister()) {
374      __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
375      __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
376    } else {
377      __ LoadImmediate(IP, Low32Bits(value));
378      __ str(IP, Address(SP, location.GetStackIndex()));
379      __ LoadImmediate(IP, High32Bits(value));
380      __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
381    }
382  } else if (instruction->AsLoadLocal() != nullptr) {
383    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
384    switch (instruction->GetType()) {
385      case Primitive::kPrimBoolean:
386      case Primitive::kPrimByte:
387      case Primitive::kPrimChar:
388      case Primitive::kPrimShort:
389      case Primitive::kPrimInt:
390      case Primitive::kPrimNot:
391        Move32(location, Location::StackSlot(stack_slot));
392        break;
393
394      case Primitive::kPrimLong:
395        Move64(location, Location::DoubleStackSlot(stack_slot));
396        break;
397
398      default:
399        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
400    }
401  } else {
402    // This can currently only happen when the instruction that requests the move
403    // is the next to be compiled.
404    DCHECK_EQ(instruction->GetNext(), move_for);
405    switch (instruction->GetType()) {
406      case Primitive::kPrimBoolean:
407      case Primitive::kPrimByte:
408      case Primitive::kPrimChar:
409      case Primitive::kPrimShort:
410      case Primitive::kPrimNot:
411      case Primitive::kPrimInt:
412        Move32(location, instruction->GetLocations()->Out());
413        break;
414
415      case Primitive::kPrimLong:
416        Move64(location, instruction->GetLocations()->Out());
417        break;
418
419      default:
420        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
421    }
422  }
423}
424
425void LocationsBuilderARM::VisitGoto(HGoto* got) {
426  got->SetLocations(nullptr);
427}
428
429void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
430  HBasicBlock* successor = got->GetSuccessor();
431  if (GetGraph()->GetExitBlock() == successor) {
432    codegen_->GenerateFrameExit();
433  } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
434    __ b(codegen_->GetLabelOf(successor));
435  }
436}
437
438void LocationsBuilderARM::VisitExit(HExit* exit) {
439  exit->SetLocations(nullptr);
440}
441
442void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
443  if (kIsDebugBuild) {
444    __ Comment("Unreachable");
445    __ bkpt(0);
446  }
447}
448
449void LocationsBuilderARM::VisitIf(HIf* if_instr) {
450  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
451  locations->SetInAt(0, Location::Any());
452  if_instr->SetLocations(locations);
453}
454
455void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
456  HInstruction* cond = if_instr->InputAt(0);
457  DCHECK(cond->IsCondition());
458  HCondition* condition = cond->AsCondition();
459  if (condition->NeedsMaterialization()) {
460    // Condition has been materialized, compare the output to 0
461    if (!if_instr->GetLocations()->InAt(0).IsRegister()) {
462      LOG(FATAL) << "Materialized condition is not in an ARM register";
463    }
464    __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
465           ShifterOperand(0));
466    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
467  } else {
468    // Condition has not been materialized, use its inputs as the comparison and its
469    // condition as the branch condition.
470    __ cmp(condition->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
471           ShifterOperand(condition->GetLocations()->InAt(1).AsArm().AsCoreRegister()));
472    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
473         ARMCondition(condition->GetCondition()));
474  }
475  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
476    __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
477  }
478}
479
480
481void LocationsBuilderARM::VisitCondition(HCondition* comp) {
482  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
483  locations->SetInAt(0, Location::RequiresRegister());
484  locations->SetInAt(1, Location::RequiresRegister());
485  locations->SetOut(Location::RequiresRegister());
486  comp->SetLocations(locations);
487}
488
489void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
490  if (comp->NeedsMaterialization()) {
491    LocationSummary* locations = comp->GetLocations();
492    __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
493           ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
494    __ it(ARMCondition(comp->GetCondition()), kItElse);
495    __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
496           ARMCondition(comp->GetCondition()));
497    __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
498           ARMOppositeCondition(comp->GetCondition()));
499  }
500}
501
502void LocationsBuilderARM::VisitEqual(HEqual* comp) {
503  VisitCondition(comp);
504}
505
506void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
507  VisitCondition(comp);
508}
509
510void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
511  VisitCondition(comp);
512}
513
514void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
515  VisitCondition(comp);
516}
517
518void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
519  VisitCondition(comp);
520}
521
522void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
523  VisitCondition(comp);
524}
525
526void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
527  VisitCondition(comp);
528}
529
530void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
531  VisitCondition(comp);
532}
533
534void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
535  VisitCondition(comp);
536}
537
538void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
539  VisitCondition(comp);
540}
541
542void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
543  VisitCondition(comp);
544}
545
546void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
547  VisitCondition(comp);
548}
549
550void LocationsBuilderARM::VisitLocal(HLocal* local) {
551  local->SetLocations(nullptr);
552}
553
554void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
555  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
556}
557
558void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
559  load->SetLocations(nullptr);
560}
561
562void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
563  // Nothing to do, this is driven by the code generator.
564}
565
566void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
567  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
568  switch (store->InputAt(1)->GetType()) {
569    case Primitive::kPrimBoolean:
570    case Primitive::kPrimByte:
571    case Primitive::kPrimChar:
572    case Primitive::kPrimShort:
573    case Primitive::kPrimInt:
574    case Primitive::kPrimNot:
575      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
576      break;
577
578    case Primitive::kPrimLong:
579      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
580      break;
581
582    default:
583      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
584  }
585  store->SetLocations(locations);
586}
587
588void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
589}
590
591void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
592  // TODO: Support constant locations.
593  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
594  locations->SetOut(Location::RequiresRegister());
595  constant->SetLocations(locations);
596}
597
598void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
599  codegen_->Move(constant, constant->GetLocations()->Out(), nullptr);
600}
601
602void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
603  // TODO: Support constant locations.
604  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
605  locations->SetOut(Location::RequiresRegister());
606  constant->SetLocations(locations);
607}
608
609void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
610  // Will be generated at use site.
611}
612
613void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
614  ret->SetLocations(nullptr);
615}
616
617void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
618  codegen_->GenerateFrameExit();
619}
620
621void LocationsBuilderARM::VisitReturn(HReturn* ret) {
622  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
623  switch (ret->InputAt(0)->GetType()) {
624    case Primitive::kPrimBoolean:
625    case Primitive::kPrimByte:
626    case Primitive::kPrimChar:
627    case Primitive::kPrimShort:
628    case Primitive::kPrimInt:
629    case Primitive::kPrimNot:
630      locations->SetInAt(0, ArmCoreLocation(R0));
631      break;
632
633    case Primitive::kPrimLong:
634      locations->SetInAt(
635          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
636      break;
637
638    default:
639      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
640  }
641
642  ret->SetLocations(locations);
643}
644
645void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
646  if (kIsDebugBuild) {
647    switch (ret->InputAt(0)->GetType()) {
648      case Primitive::kPrimBoolean:
649      case Primitive::kPrimByte:
650      case Primitive::kPrimChar:
651      case Primitive::kPrimShort:
652      case Primitive::kPrimInt:
653      case Primitive::kPrimNot:
654        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
655        break;
656
657      case Primitive::kPrimLong:
658        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
659        break;
660
661      default:
662        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
663    }
664  }
665  codegen_->GenerateFrameExit();
666}
667
668void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
669  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
670  locations->AddTemp(ArmCoreLocation(R0));
671
672  InvokeDexCallingConventionVisitor calling_convention_visitor;
673  for (size_t i = 0; i < invoke->InputCount(); i++) {
674    HInstruction* input = invoke->InputAt(i);
675    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
676  }
677
678  switch (invoke->GetType()) {
679    case Primitive::kPrimBoolean:
680    case Primitive::kPrimByte:
681    case Primitive::kPrimChar:
682    case Primitive::kPrimShort:
683    case Primitive::kPrimInt:
684    case Primitive::kPrimNot:
685      locations->SetOut(ArmCoreLocation(R0));
686      break;
687
688    case Primitive::kPrimLong:
689      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
690      break;
691
692    case Primitive::kPrimVoid:
693      break;
694
695    case Primitive::kPrimDouble:
696    case Primitive::kPrimFloat:
697      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
698      break;
699  }
700
701  invoke->SetLocations(locations);
702}
703
704void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
705  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
706}
707
708void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
709  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
710  size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
711      invoke->GetIndexInDexCache() * kArmWordSize;
712
713  // TODO: Implement all kinds of calls:
714  // 1) boot -> boot
715  // 2) app -> boot
716  // 3) app -> app
717  //
718  // Currently we implement the app -> app logic, which looks up in the resolve cache.
719
720  // temp = method;
721  LoadCurrentMethod(temp);
722  // temp = temp->dex_cache_resolved_methods_;
723  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
724  // temp = temp[index_in_cache]
725  __ ldr(temp, Address(temp, index_in_cache));
726  // LR = temp[offset_of_quick_compiled_code]
727  __ ldr(LR, Address(temp,
728                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
729  // LR()
730  __ blx(LR);
731
732  codegen_->RecordPcInfo(invoke->GetDexPc());
733}
734
735void LocationsBuilderARM::VisitAdd(HAdd* add) {
736  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
737  switch (add->GetResultType()) {
738    case Primitive::kPrimInt:
739    case Primitive::kPrimLong: {
740      locations->SetInAt(0, Location::RequiresRegister());
741      locations->SetInAt(1, Location::RequiresRegister());
742      locations->SetOut(Location::RequiresRegister());
743      break;
744    }
745
746    case Primitive::kPrimBoolean:
747    case Primitive::kPrimByte:
748    case Primitive::kPrimChar:
749    case Primitive::kPrimShort:
750      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
751      break;
752
753    default:
754      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
755  }
756  add->SetLocations(locations);
757}
758
759void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
760  LocationSummary* locations = add->GetLocations();
761  switch (add->GetResultType()) {
762    case Primitive::kPrimInt:
763      __ add(locations->Out().AsArm().AsCoreRegister(),
764             locations->InAt(0).AsArm().AsCoreRegister(),
765             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
766      break;
767
768    case Primitive::kPrimLong:
769      __ adds(locations->Out().AsArm().AsRegisterPairLow(),
770              locations->InAt(0).AsArm().AsRegisterPairLow(),
771              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
772      __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
773             locations->InAt(0).AsArm().AsRegisterPairHigh(),
774             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
775      break;
776
777    case Primitive::kPrimBoolean:
778    case Primitive::kPrimByte:
779    case Primitive::kPrimChar:
780    case Primitive::kPrimShort:
781      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
782      break;
783
784    default:
785      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
786  }
787}
788
789void LocationsBuilderARM::VisitSub(HSub* sub) {
790  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
791  switch (sub->GetResultType()) {
792    case Primitive::kPrimInt:
793    case Primitive::kPrimLong: {
794      locations->SetInAt(0, Location::RequiresRegister());
795      locations->SetInAt(1, Location::RequiresRegister());
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 sub type " << sub->GetResultType();
805      break;
806
807    default:
808      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
809  }
810  sub->SetLocations(locations);
811}
812
813void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
814  LocationSummary* locations = sub->GetLocations();
815  switch (sub->GetResultType()) {
816    case Primitive::kPrimInt:
817      __ sub(locations->Out().AsArm().AsCoreRegister(),
818             locations->InAt(0).AsArm().AsCoreRegister(),
819             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
820      break;
821
822    case Primitive::kPrimLong:
823      __ subs(locations->Out().AsArm().AsRegisterPairLow(),
824              locations->InAt(0).AsArm().AsRegisterPairLow(),
825              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
826      __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
827             locations->InAt(0).AsArm().AsRegisterPairHigh(),
828             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
829      break;
830
831    case Primitive::kPrimBoolean:
832    case Primitive::kPrimByte:
833    case Primitive::kPrimChar:
834    case Primitive::kPrimShort:
835      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
836      break;
837
838    default:
839      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
840  }
841}
842
843static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
844static constexpr size_t kRuntimeParameterCoreRegistersLength =
845    arraysize(kRuntimeParameterCoreRegisters);
846
847class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
848 public:
849  InvokeRuntimeCallingConvention()
850      : CallingConvention(kRuntimeParameterCoreRegisters,
851                          kRuntimeParameterCoreRegistersLength) {}
852
853 private:
854  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
855};
856
857void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
858  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
859  InvokeRuntimeCallingConvention calling_convention;
860  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
861  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
862  locations->SetOut(ArmCoreLocation(R0));
863  instruction->SetLocations(locations);
864}
865
866void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
867  InvokeRuntimeCallingConvention calling_convention;
868  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
869  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
870
871  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
872  __ ldr(LR, Address(TR, offset));
873  __ blx(LR);
874
875  codegen_->RecordPcInfo(instruction->GetDexPc());
876}
877
878void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
879  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
880  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
881  if (location.IsStackSlot()) {
882    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
883  } else if (location.IsDoubleStackSlot()) {
884    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
885  }
886  locations->SetOut(location);
887  instruction->SetLocations(locations);
888}
889
890void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
891  // Nothing to do, the parameter is already at its location.
892}
893
894void LocationsBuilderARM::VisitNot(HNot* instruction) {
895  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
896  locations->SetInAt(0, Location::RequiresRegister());
897  locations->SetOut(Location::RequiresRegister());
898  instruction->SetLocations(locations);
899}
900
901void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
902  LocationSummary* locations = instruction->GetLocations();
903  __ eor(locations->Out().AsArm().AsCoreRegister(),
904         locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
905}
906
907void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
908  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
909  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
910    locations->SetInAt(i, Location::Any());
911  }
912  locations->SetOut(Location::Any());
913  instruction->SetLocations(locations);
914}
915
916void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
917  LOG(FATAL) << "Unreachable";
918}
919
920void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
921  LOG(FATAL) << "Unreachable";
922}
923
924void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
925  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
926}
927
928ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
929  return codegen_->GetAssembler();
930}
931
932void ParallelMoveResolverARM::EmitMove(size_t index) {
933  MoveOperands* move = moves_.Get(index);
934  Location source = move->GetSource();
935  Location destination = move->GetDestination();
936
937  if (source.IsRegister()) {
938    if (destination.IsRegister()) {
939      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
940    } else {
941      DCHECK(destination.IsStackSlot());
942      __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
943                       SP, destination.GetStackIndex());
944    }
945  } else if (source.IsStackSlot()) {
946    if (destination.IsRegister()) {
947      __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
948                        SP, source.GetStackIndex());
949    } else {
950      DCHECK(destination.IsStackSlot());
951      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
952      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
953    }
954  } else {
955    LOG(FATAL) << "Unimplemented";
956  }
957}
958
959void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
960  __ Mov(IP, reg);
961  __ LoadFromOffset(kLoadWord, reg, SP, mem);
962  __ StoreToOffset(kStoreWord, IP, SP, mem);
963}
964
965void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
966  ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
967  int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
968  __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
969                    SP, mem1 + stack_offset);
970  __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
971  __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
972                   SP, mem2 + stack_offset);
973  __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
974}
975
976void ParallelMoveResolverARM::EmitSwap(size_t index) {
977  MoveOperands* move = moves_.Get(index);
978  Location source = move->GetSource();
979  Location destination = move->GetDestination();
980
981  if (source.IsRegister() && destination.IsRegister()) {
982    DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
983    DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
984    __ Mov(IP, source.AsArm().AsCoreRegister());
985    __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
986    __ Mov(destination.AsArm().AsCoreRegister(), IP);
987  } else if (source.IsRegister() && destination.IsStackSlot()) {
988    Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
989  } else if (source.IsStackSlot() && destination.IsRegister()) {
990    Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
991  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
992    Exchange(source.GetStackIndex(), destination.GetStackIndex());
993  } else {
994    LOG(FATAL) << "Unimplemented";
995  }
996}
997
998void ParallelMoveResolverARM::SpillScratch(int reg) {
999  __ Push(static_cast<Register>(reg));
1000}
1001
1002void ParallelMoveResolverARM::RestoreScratch(int reg) {
1003  __ Pop(static_cast<Register>(reg));
1004}
1005
1006}  // namespace arm
1007}  // namespace art
1008