blob: fe61333c8fd217e63136dad9eabab9106df54ef5 [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
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
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100191void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
192 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100193 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 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100211 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100212 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 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000230 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100231 // 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);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100234 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 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000251 }
252}
253
254void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000255 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000256}
257
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000258void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000259 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000260 if (GetGraph()->GetExitBlock() == successor) {
261 codegen_->GenerateFrameExit();
262 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
263 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000264 }
265}
266
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000267void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000268 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000269}
270
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000271void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000272 if (kIsDebugBuild) {
273 __ Comment("Unreachable");
274 __ bkpt(0);
275 }
276}
277
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000278void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000279 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100280 locations->SetInAt(0, ArmCoreLocation(R0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000281 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000282}
283
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000284void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000285 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100286 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000287 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
288 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
289 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000290 }
291}
292
293void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000294 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100295 locations->SetInAt(0, ArmCoreLocation(R0));
296 locations->SetInAt(1, ArmCoreLocation(R1));
297 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000298 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000299}
300
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000301void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
302 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100303 __ 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);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000307}
308
309void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000310 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000311}
312
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000313void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
314 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000315}
316
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000317void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100318 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000319}
320
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000321void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100322 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000323}
324
325void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000326 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100327 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 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000344 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000345}
346
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000347void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000348}
349
350void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000351 constant->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000352}
353
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000354void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000355 // Will be generated at use site.
356}
357
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100358void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
359 constant->SetLocations(nullptr);
360}
361
362void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
363 // Will be generated at use site.
364}
365
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000366void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000367 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000368}
369
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000370void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
371 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000372}
373
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000374void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000375 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100376 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
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000394 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000395}
396
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000397void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100398 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 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000417 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418}
419
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100420void LocationsBuilderARM::VisitPushArgument(HPushArgument* argument) {
421 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100422 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100423 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();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100454 }
455 argument->SetLocations(locations);
456}
457
458void InstructionCodeGeneratorARM::VisitPushArgument(HPushArgument* argument) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100459 // Nothing to do.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100460}
461
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000462void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
463 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100464 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
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000488 invoke->SetLocations(locations);
489}
490
491void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100492 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000493}
494
495void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100496 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000497 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100498 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000499
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000522void LocationsBuilderARM::VisitAdd(HAdd* add) {
523 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
524 switch (add->GetResultType()) {
525 case Primitive::kPrimInt: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100526 locations->SetInAt(0, ArmCoreLocation(R0));
527 locations->SetInAt(1, ArmCoreLocation(R1));
528 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000529 break;
530 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100531
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000548 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100549 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000550 }
551 add->SetLocations(locations);
552}
553
554void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
555 LocationSummary* locations = add->GetLocations();
556 switch (add->GetResultType()) {
557 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100558 __ add(locations->Out().AsArm().AsCoreRegister(),
559 locations->InAt(0).AsArm().AsCoreRegister(),
560 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000561 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100562
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
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000579 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100580 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000581 }
582}
583
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100584void LocationsBuilderARM::VisitSub(HSub* sub) {
585 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
586 switch (sub->GetResultType()) {
587 case Primitive::kPrimInt: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100588 locations->SetInAt(0, ArmCoreLocation(R0));
589 locations->SetInAt(1, ArmCoreLocation(R1));
590 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100591 break;
592 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100593
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
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100610 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100611 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100612 }
613 sub->SetLocations(locations);
614}
615
616void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
617 LocationSummary* locations = sub->GetLocations();
618 switch (sub->GetResultType()) {
619 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100620 __ sub(locations->Out().AsArm().AsCoreRegister(),
621 locations->InAt(0).AsArm().AsCoreRegister(),
622 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100623 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100624
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
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100641 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100643 }
644}
645
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100646static 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);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100662 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100663 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
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100671 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100672 __ ldr(LR, Address(TR, offset));
673 __ blx(LR);
674
675 codegen_->RecordPcInfo(instruction->GetDexPc());
676}
677
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100678void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
679 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
680 InvokeDexCallingConvention calling_convention;
681 uint32_t argument_index = instruction->GetIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100682 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();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100712 }
713 instruction->SetLocations(locations);
714}
715
716void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100717 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100718}
719
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100720void LocationsBuilderARM::VisitNot(HNot* instruction) {
721 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100722 locations->SetInAt(0, ArmCoreLocation(R0));
723 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100724 instruction->SetLocations(locations);
725}
726
727void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
728 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100729 __ eor(locations->Out().AsArm().AsCoreRegister(),
730 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100731}
732
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000733} // namespace arm
734} // namespace art