blob: cdd9696fcd1ad431844df978674b22015144ed0f [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010020#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000021
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000022#include "mirror/array.h"
23#include "mirror/art_method.h"
24
Nicolas Geoffray787c3072014-03-17 10:20:19 +000025#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000026
27namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010028
29arm::ArmManagedRegister Location::AsArm() const {
30 return reg().AsArm();
31}
32
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace arm {
34
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010035static constexpr int kNumberOfPushedRegistersAtEntry = 1;
36static constexpr int kCurrentMethodStackOffset = 0;
37
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010038static Location ArmCoreLocation(Register reg) {
39 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
40}
41
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010042InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
43 : HGraphVisitor(graph),
44 assembler_(codegen->GetAssembler()),
45 codegen_(codegen) {}
46
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000047void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000048 core_spill_mask_ |= (1 << LR);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010049 __ PushList((1 << LR));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000050
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010051 // 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.
Nicolas Geoffray707c8092014-04-04 10:50:14 +010056 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000057 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000058}
59
60void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +010061 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010062 __ PopList((1 << PC));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000063}
64
65void CodeGeneratorARM::Bind(Label* label) {
66 __ Bind(label);
67}
68
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010069int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010070 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 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000084}
85
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010086static 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
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100104class 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
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100156void 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
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100243void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
244 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100245 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 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100263 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100264 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 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000282 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100283 // 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);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100286 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 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000303 }
304}
305
306void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000307 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000308}
309
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000310void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000311 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000312 if (GetGraph()->GetExitBlock() == successor) {
313 codegen_->GenerateFrameExit();
314 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
315 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000316 }
317}
318
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000319void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000320 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000321}
322
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000323void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000324 if (kIsDebugBuild) {
325 __ Comment("Unreachable");
326 __ bkpt(0);
327 }
328}
329
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000330void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000331 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100332 locations->SetInAt(0, ArmCoreLocation(R0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000333 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000334}
335
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000336void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000337 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100338 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000339 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
340 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
341 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000342 }
343}
344
345void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000346 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100347 locations->SetInAt(0, ArmCoreLocation(R0));
348 locations->SetInAt(1, ArmCoreLocation(R1));
349 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000350 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000351}
352
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000353void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
354 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100355 __ 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);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000359}
360
361void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000362 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000363}
364
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000365void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
366 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000367}
368
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000369void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100370 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000371}
372
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000373void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100374 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000375}
376
377void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000378 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100379 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 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000396 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000397}
398
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000399void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000400}
401
402void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000403 constant->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000404}
405
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000406void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000407 // Will be generated at use site.
408}
409
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100410void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
411 constant->SetLocations(nullptr);
412}
413
414void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
415 // Will be generated at use site.
416}
417
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000419 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000420}
421
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000422void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
423 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000424}
425
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000426void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000427 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100428 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
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000446 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000447}
448
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000449void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100450 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 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000469 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000470}
471
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000472void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
473 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100474 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100475
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()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100483 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
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000505 invoke->SetLocations(locations);
506}
507
508void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100509 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000510}
511
512void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100513 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000514 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100515 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000516
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000539void LocationsBuilderARM::VisitAdd(HAdd* add) {
540 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
541 switch (add->GetResultType()) {
542 case Primitive::kPrimInt: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100543 locations->SetInAt(0, ArmCoreLocation(R0));
544 locations->SetInAt(1, ArmCoreLocation(R1));
545 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000546 break;
547 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100548
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000565 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100566 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000567 }
568 add->SetLocations(locations);
569}
570
571void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
572 LocationSummary* locations = add->GetLocations();
573 switch (add->GetResultType()) {
574 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100575 __ add(locations->Out().AsArm().AsCoreRegister(),
576 locations->InAt(0).AsArm().AsCoreRegister(),
577 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000578 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100579
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000596 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100597 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000598 }
599}
600
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100601void LocationsBuilderARM::VisitSub(HSub* sub) {
602 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
603 switch (sub->GetResultType()) {
604 case Primitive::kPrimInt: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100605 locations->SetInAt(0, ArmCoreLocation(R0));
606 locations->SetInAt(1, ArmCoreLocation(R1));
607 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100608 break;
609 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100610
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
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100627 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100628 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100629 }
630 sub->SetLocations(locations);
631}
632
633void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
634 LocationSummary* locations = sub->GetLocations();
635 switch (sub->GetResultType()) {
636 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100637 __ sub(locations->Out().AsArm().AsCoreRegister(),
638 locations->InAt(0).AsArm().AsCoreRegister(),
639 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100640 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100641
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
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100658 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100659 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100660 }
661}
662
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100663static 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);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100679 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100680 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
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100688 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100689 __ ldr(LR, Address(TR, offset));
690 __ blx(LR);
691
692 codegen_->RecordPcInfo(instruction->GetDexPc());
693}
694
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100695void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
696 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
697 InvokeDexCallingConvention calling_convention;
698 uint32_t argument_index = instruction->GetIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 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();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100729 }
730 instruction->SetLocations(locations);
731}
732
733void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100734 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100735}
736
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100737void LocationsBuilderARM::VisitNot(HNot* instruction) {
738 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100739 locations->SetInAt(0, ArmCoreLocation(R0));
740 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100741 instruction->SetLocations(locations);
742}
743
744void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
745 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100746 __ eor(locations->Out().AsArm().AsCoreRegister(),
747 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100748}
749
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000750} // namespace arm
751} // namespace art