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