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