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