code_generator_arm.cc revision b0fa5dc7769c1e054032f39de0a3f6d6dd06f8cf
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#include "utils/assembler.h"
19#include "utils/arm/assembler_arm.h"
20#include "utils/arm/managed_register_arm.h"
21
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "mirror/array.h"
24#include "mirror/art_method.h"
25#include "thread.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
37static constexpr int kNumberOfPushedRegistersAtEntry = 1;
38static constexpr int kCurrentMethodStackOffset = 0;
39
40CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
41    : CodeGenerator(graph, kNumberOfRegIds),
42      location_builder_(graph, this),
43      instruction_visitor_(graph, this) {}
44
45static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
46  return blocked_registers + kNumberOfAllocIds;
47}
48
49ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
50                                                       bool* blocked_registers) const {
51  switch (type) {
52    case Primitive::kPrimLong: {
53      size_t reg = AllocateFreeRegisterInternal(
54          GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
55      ArmManagedRegister pair =
56          ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
57      blocked_registers[pair.AsRegisterPairLow()] = true;
58      blocked_registers[pair.AsRegisterPairHigh()] = true;
59      return pair;
60    }
61
62    case Primitive::kPrimByte:
63    case Primitive::kPrimBoolean:
64    case Primitive::kPrimChar:
65    case Primitive::kPrimShort:
66    case Primitive::kPrimInt:
67    case Primitive::kPrimNot: {
68      size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
69      return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
70    }
71
72    case Primitive::kPrimFloat:
73    case Primitive::kPrimDouble:
74      LOG(FATAL) << "Unimplemented register type " << type;
75
76    case Primitive::kPrimVoid:
77      LOG(FATAL) << "Unreachable type " << type;
78  }
79
80  return ManagedRegister::NoRegister();
81}
82
83void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
84  bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
85
86  // Don't allocate the dalvik style register pair passing.
87  blocked_register_pairs[R1_R2] = true;
88
89  // Stack register, LR and PC are always reserved.
90  blocked_registers[SP] = true;
91  blocked_registers[LR] = true;
92  blocked_registers[PC] = true;
93
94  // Reserve R4 for suspend check.
95  blocked_registers[R4] = true;
96  blocked_register_pairs[R4_R5] = true;
97
98  // Reserve thread register.
99  blocked_registers[TR] = true;
100
101  // TODO: We currently don't use Quick's callee saved registers.
102  blocked_registers[R5] = true;
103  blocked_registers[R6] = true;
104  blocked_registers[R7] = true;
105  blocked_registers[R8] = true;
106  blocked_registers[R10] = true;
107  blocked_registers[R11] = true;
108  blocked_register_pairs[R6_R7] = true;
109}
110
111size_t CodeGeneratorARM::GetNumberOfRegisters() const {
112  return kNumberOfRegIds;
113}
114
115static Location ArmCoreLocation(Register reg) {
116  return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
117}
118
119InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
120      : HGraphVisitor(graph),
121        assembler_(codegen->GetAssembler()),
122        codegen_(codegen) {}
123
124void CodeGeneratorARM::GenerateFrameEntry() {
125  core_spill_mask_ |= (1 << LR);
126  __ PushList((1 << LR));
127
128  SetFrameSize(RoundUp(
129      (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
130      + kVRegSize  // filler
131      + kArmWordSize  // Art method
132      + kNumberOfPushedRegistersAtEntry * kArmWordSize,
133      kStackAlignment));
134  // The return PC has already been pushed on the stack.
135  __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
136  __ str(R0, Address(SP, 0));
137}
138
139void CodeGeneratorARM::GenerateFrameExit() {
140  __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
141  __ PopList((1 << PC));
142}
143
144void CodeGeneratorARM::Bind(Label* label) {
145  __ Bind(label);
146}
147
148int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
149  uint16_t reg_number = local->GetRegNumber();
150  uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
151  uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
152  if (reg_number >= number_of_vregs - number_of_in_vregs) {
153    // Local is a parameter of the method. It is stored in the caller's frame.
154    return GetFrameSize() + kArmWordSize  // ART method
155                          + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
156  } else {
157    // Local is a temporary in this method. It is stored in this method's frame.
158    return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
159                          - kVRegSize  // filler.
160                          - (number_of_vregs * kVRegSize)
161                          + (reg_number * kVRegSize);
162  }
163}
164
165Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
166  switch (load->GetType()) {
167    case Primitive::kPrimLong:
168      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
169      break;
170
171    case Primitive::kPrimInt:
172    case Primitive::kPrimNot:
173      return Location::StackSlot(GetStackSlot(load->GetLocal()));
174
175    case Primitive::kPrimFloat:
176    case Primitive::kPrimDouble:
177      LOG(FATAL) << "Unimplemented type " << load->GetType();
178
179    case Primitive::kPrimBoolean:
180    case Primitive::kPrimByte:
181    case Primitive::kPrimChar:
182    case Primitive::kPrimShort:
183    case Primitive::kPrimVoid:
184      LOG(FATAL) << "Unexpected type " << load->GetType();
185  }
186
187  LOG(FATAL) << "Unreachable";
188  return Location();
189}
190
191Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
192  switch (type) {
193    case Primitive::kPrimBoolean:
194    case Primitive::kPrimByte:
195    case Primitive::kPrimChar:
196    case Primitive::kPrimShort:
197    case Primitive::kPrimInt:
198    case Primitive::kPrimNot: {
199      uint32_t index = gp_index_++;
200      if (index < calling_convention.GetNumberOfRegisters()) {
201        return ArmCoreLocation(calling_convention.GetRegisterAt(index));
202      } else {
203        return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
204      }
205    }
206
207    case Primitive::kPrimLong: {
208      uint32_t index = gp_index_;
209      gp_index_ += 2;
210      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
211        return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
212            calling_convention.GetRegisterPairAt(index)));
213      } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
214        return Location::QuickParameter(index);
215      } else {
216        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
217      }
218    }
219
220    case Primitive::kPrimDouble:
221    case Primitive::kPrimFloat:
222      LOG(FATAL) << "Unimplemented parameter type " << type;
223      break;
224
225    case Primitive::kPrimVoid:
226      LOG(FATAL) << "Unexpected parameter type " << type;
227      break;
228  }
229  return Location();
230}
231
232void CodeGeneratorARM::Move32(Location destination, Location source) {
233  if (source.Equals(destination)) {
234    return;
235  }
236  if (destination.IsRegister()) {
237    if (source.IsRegister()) {
238      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
239    } else {
240      __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
241    }
242  } else {
243    DCHECK(destination.IsStackSlot());
244    if (source.IsRegister()) {
245      __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
246    } else {
247      __ ldr(R0, Address(SP, source.GetStackIndex()));
248      __ str(R0, Address(SP, destination.GetStackIndex()));
249    }
250  }
251}
252
253void CodeGeneratorARM::Move64(Location destination, Location source) {
254  if (source.Equals(destination)) {
255    return;
256  }
257  if (destination.IsRegister()) {
258    if (source.IsRegister()) {
259      __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
260      __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
261    } else if (source.IsQuickParameter()) {
262      uint32_t argument_index = source.GetQuickParameterIndex();
263      InvokeDexCallingConvention calling_convention;
264      __ Mov(destination.AsArm().AsRegisterPairLow(),
265             calling_convention.GetRegisterAt(argument_index));
266      __ ldr(destination.AsArm().AsRegisterPairHigh(),
267             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
268    } else {
269      DCHECK(source.IsDoubleStackSlot());
270      if (destination.AsArm().AsRegisterPair() == R1_R2) {
271        __ ldr(R1, Address(SP, source.GetStackIndex()));
272        __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
273      } else {
274        __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
275                          SP, source.GetStackIndex());
276      }
277    }
278  } else if (destination.IsQuickParameter()) {
279    InvokeDexCallingConvention calling_convention;
280    uint32_t argument_index = destination.GetQuickParameterIndex();
281    if (source.IsRegister()) {
282      __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
283      __ str(source.AsArm().AsRegisterPairHigh(),
284             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
285    } else {
286      DCHECK(source.IsDoubleStackSlot());
287      __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
288      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
289      __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
290    }
291  } else {
292    DCHECK(destination.IsDoubleStackSlot());
293    if (source.IsRegister()) {
294      if (source.AsArm().AsRegisterPair() == R1_R2) {
295        __ str(R1, Address(SP, destination.GetStackIndex()));
296        __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
297      } else {
298        __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
299                         SP, destination.GetStackIndex());
300      }
301    } else if (source.IsQuickParameter()) {
302      InvokeDexCallingConvention calling_convention;
303      uint32_t argument_index = source.GetQuickParameterIndex();
304      __ str(calling_convention.GetRegisterAt(argument_index),
305             Address(SP, destination.GetStackIndex()));
306      __ ldr(R0,
307             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
308      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
309    } else {
310      DCHECK(source.IsDoubleStackSlot());
311      __ ldr(R0, Address(SP, source.GetStackIndex()));
312      __ str(R0, Address(SP, destination.GetStackIndex()));
313      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
314      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
315    }
316  }
317}
318
319void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
320  if (instruction->AsIntConstant() != nullptr) {
321    int32_t value = instruction->AsIntConstant()->GetValue();
322    if (location.IsRegister()) {
323      __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
324    } else {
325      __ LoadImmediate(R0, value);
326      __ str(R0, Address(SP, location.GetStackIndex()));
327    }
328  } else if (instruction->AsLongConstant() != nullptr) {
329    int64_t value = instruction->AsLongConstant()->GetValue();
330    if (location.IsRegister()) {
331      __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
332      __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
333    } else {
334      __ LoadImmediate(R0, Low32Bits(value));
335      __ str(R0, Address(SP, location.GetStackIndex()));
336      __ LoadImmediate(R0, High32Bits(value));
337      __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize)));
338    }
339  } else if (instruction->AsLoadLocal() != nullptr) {
340    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
341    switch (instruction->GetType()) {
342      case Primitive::kPrimBoolean:
343      case Primitive::kPrimByte:
344      case Primitive::kPrimChar:
345      case Primitive::kPrimShort:
346      case Primitive::kPrimInt:
347      case Primitive::kPrimNot:
348        Move32(location, Location::StackSlot(stack_slot));
349        break;
350
351      case Primitive::kPrimLong:
352        Move64(location, Location::DoubleStackSlot(stack_slot));
353        break;
354
355      default:
356        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
357    }
358  } else {
359    // This can currently only happen when the instruction that requests the move
360    // is the next to be compiled.
361    DCHECK_EQ(instruction->GetNext(), move_for);
362    switch (instruction->GetType()) {
363      case Primitive::kPrimBoolean:
364      case Primitive::kPrimByte:
365      case Primitive::kPrimChar:
366      case Primitive::kPrimShort:
367      case Primitive::kPrimNot:
368      case Primitive::kPrimInt:
369        Move32(location, instruction->GetLocations()->Out());
370        break;
371
372      case Primitive::kPrimLong:
373        Move64(location, instruction->GetLocations()->Out());
374        break;
375
376      default:
377        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
378    }
379  }
380}
381
382void LocationsBuilderARM::VisitGoto(HGoto* got) {
383  got->SetLocations(nullptr);
384}
385
386void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
387  HBasicBlock* successor = got->GetSuccessor();
388  if (GetGraph()->GetExitBlock() == successor) {
389    codegen_->GenerateFrameExit();
390  } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
391    __ b(codegen_->GetLabelOf(successor));
392  }
393}
394
395void LocationsBuilderARM::VisitExit(HExit* exit) {
396  exit->SetLocations(nullptr);
397}
398
399void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
400  if (kIsDebugBuild) {
401    __ Comment("Unreachable");
402    __ bkpt(0);
403  }
404}
405
406void LocationsBuilderARM::VisitIf(HIf* if_instr) {
407  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
408  locations->SetInAt(0, Location::RequiresRegister());
409  if_instr->SetLocations(locations);
410}
411
412void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
413  // TODO: Generate the input as a condition, instead of materializing in a register.
414  __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
415  __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
416  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
417    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
418  }
419}
420
421void LocationsBuilderARM::VisitEqual(HEqual* equal) {
422  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
423  locations->SetInAt(0, Location::RequiresRegister());
424  locations->SetInAt(1, Location::RequiresRegister());
425  locations->SetOut(Location::RequiresRegister());
426  equal->SetLocations(locations);
427}
428
429void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
430  LocationSummary* locations = equal->GetLocations();
431  __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
432         ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
433  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
434  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
435}
436
437void LocationsBuilderARM::VisitLocal(HLocal* local) {
438  local->SetLocations(nullptr);
439}
440
441void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
442  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
443}
444
445void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
446  load->SetLocations(nullptr);
447}
448
449void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
450  // Nothing to do, this is driven by the code generator.
451}
452
453void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
454  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
455  switch (store->InputAt(1)->GetType()) {
456    case Primitive::kPrimBoolean:
457    case Primitive::kPrimByte:
458    case Primitive::kPrimChar:
459    case Primitive::kPrimShort:
460    case Primitive::kPrimInt:
461    case Primitive::kPrimNot:
462      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
463      break;
464
465    case Primitive::kPrimLong:
466      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
467      break;
468
469    default:
470      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
471  }
472  store->SetLocations(locations);
473}
474
475void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
476}
477
478void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
479  constant->SetLocations(nullptr);
480}
481
482void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
483  // Will be generated at use site.
484}
485
486void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
487  constant->SetLocations(nullptr);
488}
489
490void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
491  // Will be generated at use site.
492}
493
494void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
495  ret->SetLocations(nullptr);
496}
497
498void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
499  codegen_->GenerateFrameExit();
500}
501
502void LocationsBuilderARM::VisitReturn(HReturn* ret) {
503  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
504  switch (ret->InputAt(0)->GetType()) {
505    case Primitive::kPrimBoolean:
506    case Primitive::kPrimByte:
507    case Primitive::kPrimChar:
508    case Primitive::kPrimShort:
509    case Primitive::kPrimInt:
510    case Primitive::kPrimNot:
511      locations->SetInAt(0, ArmCoreLocation(R0));
512      break;
513
514    case Primitive::kPrimLong:
515      locations->SetInAt(
516          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
517      break;
518
519    default:
520      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
521  }
522
523  ret->SetLocations(locations);
524}
525
526void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
527  if (kIsDebugBuild) {
528    switch (ret->InputAt(0)->GetType()) {
529      case Primitive::kPrimBoolean:
530      case Primitive::kPrimByte:
531      case Primitive::kPrimChar:
532      case Primitive::kPrimShort:
533      case Primitive::kPrimInt:
534      case Primitive::kPrimNot:
535        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
536        break;
537
538      case Primitive::kPrimLong:
539        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
540        break;
541
542      default:
543        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
544    }
545  }
546  codegen_->GenerateFrameExit();
547}
548
549void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
550  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
551  locations->AddTemp(Location::RequiresRegister());
552
553  InvokeDexCallingConventionVisitor calling_convention_visitor;
554  for (size_t i = 0; i < invoke->InputCount(); i++) {
555    HInstruction* input = invoke->InputAt(i);
556    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
557  }
558
559  switch (invoke->GetType()) {
560    case Primitive::kPrimBoolean:
561    case Primitive::kPrimByte:
562    case Primitive::kPrimChar:
563    case Primitive::kPrimShort:
564    case Primitive::kPrimInt:
565    case Primitive::kPrimNot:
566      locations->SetOut(ArmCoreLocation(R0));
567      break;
568
569    case Primitive::kPrimLong:
570      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
571      break;
572
573    case Primitive::kPrimVoid:
574      break;
575
576    case Primitive::kPrimDouble:
577    case Primitive::kPrimFloat:
578      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
579      break;
580  }
581
582  invoke->SetLocations(locations);
583}
584
585void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
586  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
587}
588
589void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
590  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
591  size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
592      invoke->GetIndexInDexCache() * kArmWordSize;
593
594  // TODO: Implement all kinds of calls:
595  // 1) boot -> boot
596  // 2) app -> boot
597  // 3) app -> app
598  //
599  // Currently we implement the app -> app logic, which looks up in the resolve cache.
600
601  // temp = method;
602  LoadCurrentMethod(temp);
603  // temp = temp->dex_cache_resolved_methods_;
604  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
605  // temp = temp[index_in_cache]
606  __ ldr(temp, Address(temp, index_in_cache));
607  // LR = temp[offset_of_quick_compiled_code]
608  __ ldr(LR, Address(temp,
609                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
610  // LR()
611  __ blx(LR);
612
613  codegen_->RecordPcInfo(invoke->GetDexPc());
614}
615
616void LocationsBuilderARM::VisitAdd(HAdd* add) {
617  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
618  switch (add->GetResultType()) {
619    case Primitive::kPrimInt:
620    case Primitive::kPrimLong: {
621      locations->SetInAt(0, Location::RequiresRegister());
622      locations->SetInAt(1, Location::RequiresRegister());
623      locations->SetOut(Location::RequiresRegister());
624      break;
625    }
626
627    case Primitive::kPrimBoolean:
628    case Primitive::kPrimByte:
629    case Primitive::kPrimChar:
630    case Primitive::kPrimShort:
631      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
632      break;
633
634    default:
635      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
636  }
637  add->SetLocations(locations);
638}
639
640void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
641  LocationSummary* locations = add->GetLocations();
642  switch (add->GetResultType()) {
643    case Primitive::kPrimInt:
644      __ add(locations->Out().AsArm().AsCoreRegister(),
645             locations->InAt(0).AsArm().AsCoreRegister(),
646             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
647      break;
648
649    case Primitive::kPrimLong:
650      __ adds(locations->Out().AsArm().AsRegisterPairLow(),
651              locations->InAt(0).AsArm().AsRegisterPairLow(),
652              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
653      __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
654             locations->InAt(0).AsArm().AsRegisterPairHigh(),
655             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
656      break;
657
658    case Primitive::kPrimBoolean:
659    case Primitive::kPrimByte:
660    case Primitive::kPrimChar:
661    case Primitive::kPrimShort:
662      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
663      break;
664
665    default:
666      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
667  }
668}
669
670void LocationsBuilderARM::VisitSub(HSub* sub) {
671  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
672  switch (sub->GetResultType()) {
673    case Primitive::kPrimInt:
674    case Primitive::kPrimLong: {
675      locations->SetInAt(0, Location::RequiresRegister());
676      locations->SetInAt(1, Location::RequiresRegister());
677      locations->SetOut(Location::RequiresRegister());
678      break;
679    }
680
681    case Primitive::kPrimBoolean:
682    case Primitive::kPrimByte:
683    case Primitive::kPrimChar:
684    case Primitive::kPrimShort:
685      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
686      break;
687
688    default:
689      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
690  }
691  sub->SetLocations(locations);
692}
693
694void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
695  LocationSummary* locations = sub->GetLocations();
696  switch (sub->GetResultType()) {
697    case Primitive::kPrimInt:
698      __ sub(locations->Out().AsArm().AsCoreRegister(),
699             locations->InAt(0).AsArm().AsCoreRegister(),
700             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
701      break;
702
703    case Primitive::kPrimLong:
704      __ subs(locations->Out().AsArm().AsRegisterPairLow(),
705              locations->InAt(0).AsArm().AsRegisterPairLow(),
706              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
707      __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
708             locations->InAt(0).AsArm().AsRegisterPairHigh(),
709             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
710      break;
711
712    case Primitive::kPrimBoolean:
713    case Primitive::kPrimByte:
714    case Primitive::kPrimChar:
715    case Primitive::kPrimShort:
716      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
717      break;
718
719    default:
720      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
721  }
722}
723
724static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
725static constexpr size_t kRuntimeParameterCoreRegistersLength =
726    arraysize(kRuntimeParameterCoreRegisters);
727
728class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
729 public:
730  InvokeRuntimeCallingConvention()
731      : CallingConvention(kRuntimeParameterCoreRegisters,
732                          kRuntimeParameterCoreRegistersLength) {}
733
734 private:
735  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
736};
737
738void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
739  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
740  InvokeRuntimeCallingConvention calling_convention;
741  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
742  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
743  locations->SetOut(ArmCoreLocation(R0));
744  instruction->SetLocations(locations);
745}
746
747void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
748  InvokeRuntimeCallingConvention calling_convention;
749  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
750  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
751
752  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
753  __ ldr(LR, Address(TR, offset));
754  __ blx(LR);
755
756  codegen_->RecordPcInfo(instruction->GetDexPc());
757}
758
759void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
760  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
761  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
762  if (location.IsStackSlot()) {
763    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
764  } else if (location.IsDoubleStackSlot()) {
765    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
766  }
767  locations->SetOut(location);
768  instruction->SetLocations(locations);
769}
770
771void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
772  // Nothing to do, the parameter is already at its location.
773}
774
775void LocationsBuilderARM::VisitNot(HNot* instruction) {
776  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
777  locations->SetInAt(0, Location::RequiresRegister());
778  locations->SetOut(Location::RequiresRegister());
779  instruction->SetLocations(locations);
780}
781
782void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
783  LocationSummary* locations = instruction->GetLocations();
784  __ eor(locations->Out().AsArm().AsCoreRegister(),
785         locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
786}
787
788void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
789  LOG(FATAL) << "Unimplemented";
790}
791
792void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
793  LOG(FATAL) << "Unimplemented";
794}
795
796}  // namespace arm
797}  // namespace art
798