blob: e888cc1d6e752d262113e1c32640ae925224b4af [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
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070022#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000023#include "mirror/array.h"
24#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070025#include "thread.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000026
Nicolas Geoffray787c3072014-03-17 10:20:19 +000027#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000028
29namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010030
31arm::ArmManagedRegister Location::AsArm() const {
32 return reg().AsArm();
33}
34
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace arm {
36
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010037static constexpr int kNumberOfPushedRegistersAtEntry = 1;
38static constexpr int kCurrentMethodStackOffset = 0;
39
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010040void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
41 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
42}
43
44void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
45 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
46}
47
Nicolas Geoffraya7aca372014-04-28 17:47:12 +010048CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
49 : CodeGenerator(graph, kNumberOfRegIds),
50 location_builder_(graph, this),
51 instruction_visitor_(graph, this) {}
52
53static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
54 return blocked_registers + kNumberOfAllocIds;
55}
56
57ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
58 bool* blocked_registers) const {
59 switch (type) {
60 case Primitive::kPrimLong: {
61 size_t reg = AllocateFreeRegisterInternal(
62 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
63 ArmManagedRegister pair =
64 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
65 blocked_registers[pair.AsRegisterPairLow()] = true;
66 blocked_registers[pair.AsRegisterPairHigh()] = true;
67 return pair;
68 }
69
70 case Primitive::kPrimByte:
71 case Primitive::kPrimBoolean:
72 case Primitive::kPrimChar:
73 case Primitive::kPrimShort:
74 case Primitive::kPrimInt:
75 case Primitive::kPrimNot: {
76 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
77 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
78 }
79
80 case Primitive::kPrimFloat:
81 case Primitive::kPrimDouble:
82 LOG(FATAL) << "Unimplemented register type " << type;
83
84 case Primitive::kPrimVoid:
85 LOG(FATAL) << "Unreachable type " << type;
86 }
87
88 return ManagedRegister::NoRegister();
89}
90
91void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
92 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
93
94 // Don't allocate the dalvik style register pair passing.
95 blocked_register_pairs[R1_R2] = true;
96
97 // Stack register, LR and PC are always reserved.
98 blocked_registers[SP] = true;
99 blocked_registers[LR] = true;
100 blocked_registers[PC] = true;
101
102 // Reserve R4 for suspend check.
103 blocked_registers[R4] = true;
104 blocked_register_pairs[R4_R5] = true;
105
106 // Reserve thread register.
107 blocked_registers[TR] = true;
108
109 // TODO: We currently don't use Quick's callee saved registers.
110 blocked_registers[R5] = true;
111 blocked_registers[R6] = true;
112 blocked_registers[R7] = true;
113 blocked_registers[R8] = true;
114 blocked_registers[R10] = true;
115 blocked_registers[R11] = true;
116 blocked_register_pairs[R6_R7] = true;
117}
118
119size_t CodeGeneratorARM::GetNumberOfRegisters() const {
120 return kNumberOfRegIds;
121}
122
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100123static Location ArmCoreLocation(Register reg) {
124 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
125}
126
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100127InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
128 : HGraphVisitor(graph),
129 assembler_(codegen->GetAssembler()),
130 codegen_(codegen) {}
131
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000132void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000133 core_spill_mask_ |= (1 << LR);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100134 __ PushList((1 << LR));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000135
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100136 SetFrameSize(RoundUp(
137 (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
138 + kVRegSize // filler
139 + kArmWordSize // Art method
140 + kNumberOfPushedRegistersAtEntry * kArmWordSize,
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100141 kStackAlignment));
142 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100143 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000144 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000145}
146
147void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100148 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100149 __ PopList((1 << PC));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150}
151
152void CodeGeneratorARM::Bind(Label* label) {
153 __ Bind(label);
154}
155
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100156int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100157 uint16_t reg_number = local->GetRegNumber();
158 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
159 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
160 if (reg_number >= number_of_vregs - number_of_in_vregs) {
161 // Local is a parameter of the method. It is stored in the caller's frame.
162 return GetFrameSize() + kArmWordSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100163 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100164 } else {
165 // Local is a temporary in this method. It is stored in this method's frame.
166 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100167 - kVRegSize // filler.
168 - (number_of_vregs * kVRegSize)
169 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100170 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000171}
172
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100173Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
174 switch (load->GetType()) {
175 case Primitive::kPrimLong:
176 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
177 break;
178
179 case Primitive::kPrimInt:
180 case Primitive::kPrimNot:
181 return Location::StackSlot(GetStackSlot(load->GetLocal()));
182
183 case Primitive::kPrimFloat:
184 case Primitive::kPrimDouble:
185 LOG(FATAL) << "Unimplemented type " << load->GetType();
186
187 case Primitive::kPrimBoolean:
188 case Primitive::kPrimByte:
189 case Primitive::kPrimChar:
190 case Primitive::kPrimShort:
191 case Primitive::kPrimVoid:
192 LOG(FATAL) << "Unexpected type " << load->GetType();
193 }
194
195 LOG(FATAL) << "Unreachable";
196 return Location();
197}
198
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100199Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
200 switch (type) {
201 case Primitive::kPrimBoolean:
202 case Primitive::kPrimByte:
203 case Primitive::kPrimChar:
204 case Primitive::kPrimShort:
205 case Primitive::kPrimInt:
206 case Primitive::kPrimNot: {
207 uint32_t index = gp_index_++;
208 if (index < calling_convention.GetNumberOfRegisters()) {
209 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
210 } else {
211 return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100212 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100213 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100214
215 case Primitive::kPrimLong: {
216 uint32_t index = gp_index_;
217 gp_index_ += 2;
218 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
219 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
220 calling_convention.GetRegisterPairAt(index)));
221 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
222 return Location::QuickParameter(index);
223 } else {
224 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
225 }
226 }
227
228 case Primitive::kPrimDouble:
229 case Primitive::kPrimFloat:
230 LOG(FATAL) << "Unimplemented parameter type " << type;
231 break;
232
233 case Primitive::kPrimVoid:
234 LOG(FATAL) << "Unexpected parameter type " << type;
235 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100236 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100237 return Location();
238}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100239
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100240void CodeGeneratorARM::Move32(Location destination, Location source) {
241 if (source.Equals(destination)) {
242 return;
243 }
244 if (destination.IsRegister()) {
245 if (source.IsRegister()) {
246 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
247 } else {
248 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
249 }
250 } else {
251 DCHECK(destination.IsStackSlot());
252 if (source.IsRegister()) {
253 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
254 } else {
255 __ ldr(R0, Address(SP, source.GetStackIndex()));
256 __ str(R0, Address(SP, destination.GetStackIndex()));
257 }
258 }
259}
260
261void CodeGeneratorARM::Move64(Location destination, Location source) {
262 if (source.Equals(destination)) {
263 return;
264 }
265 if (destination.IsRegister()) {
266 if (source.IsRegister()) {
267 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
268 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
269 } else if (source.IsQuickParameter()) {
270 uint32_t argument_index = source.GetQuickParameterIndex();
271 InvokeDexCallingConvention calling_convention;
272 __ Mov(destination.AsArm().AsRegisterPairLow(),
273 calling_convention.GetRegisterAt(argument_index));
274 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100275 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100276 } else {
277 DCHECK(source.IsDoubleStackSlot());
278 if (destination.AsArm().AsRegisterPair() == R1_R2) {
279 __ ldr(R1, Address(SP, source.GetStackIndex()));
280 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
281 } else {
282 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
283 SP, source.GetStackIndex());
284 }
285 }
286 } else if (destination.IsQuickParameter()) {
287 InvokeDexCallingConvention calling_convention;
288 uint32_t argument_index = destination.GetQuickParameterIndex();
289 if (source.IsRegister()) {
290 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
291 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100292 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100293 } else {
294 DCHECK(source.IsDoubleStackSlot());
295 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
296 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100297 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100298 }
299 } else {
300 DCHECK(destination.IsDoubleStackSlot());
301 if (source.IsRegister()) {
302 if (source.AsArm().AsRegisterPair() == R1_R2) {
303 __ str(R1, Address(SP, destination.GetStackIndex()));
304 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
305 } else {
306 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
307 SP, destination.GetStackIndex());
308 }
309 } else if (source.IsQuickParameter()) {
310 InvokeDexCallingConvention calling_convention;
311 uint32_t argument_index = source.GetQuickParameterIndex();
312 __ str(calling_convention.GetRegisterAt(argument_index),
313 Address(SP, destination.GetStackIndex()));
314 __ ldr(R0,
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100315 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100316 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
317 } else {
318 DCHECK(source.IsDoubleStackSlot());
319 __ ldr(R0, Address(SP, source.GetStackIndex()));
320 __ str(R0, Address(SP, destination.GetStackIndex()));
321 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
322 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
323 }
324 }
325}
326
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100327void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
328 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100329 int32_t value = instruction->AsIntConstant()->GetValue();
330 if (location.IsRegister()) {
331 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
332 } else {
333 __ LoadImmediate(R0, value);
334 __ str(R0, Address(SP, location.GetStackIndex()));
335 }
336 } else if (instruction->AsLongConstant() != nullptr) {
337 int64_t value = instruction->AsLongConstant()->GetValue();
338 if (location.IsRegister()) {
339 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
340 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
341 } else {
342 __ LoadImmediate(R0, Low32Bits(value));
343 __ str(R0, Address(SP, location.GetStackIndex()));
344 __ LoadImmediate(R0, High32Bits(value));
345 __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize)));
346 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100347 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100348 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
349 switch (instruction->GetType()) {
350 case Primitive::kPrimBoolean:
351 case Primitive::kPrimByte:
352 case Primitive::kPrimChar:
353 case Primitive::kPrimShort:
354 case Primitive::kPrimInt:
355 case Primitive::kPrimNot:
356 Move32(location, Location::StackSlot(stack_slot));
357 break;
358
359 case Primitive::kPrimLong:
360 Move64(location, Location::DoubleStackSlot(stack_slot));
361 break;
362
363 default:
364 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
365 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000366 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100367 // This can currently only happen when the instruction that requests the move
368 // is the next to be compiled.
369 DCHECK_EQ(instruction->GetNext(), move_for);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100370 switch (instruction->GetType()) {
371 case Primitive::kPrimBoolean:
372 case Primitive::kPrimByte:
373 case Primitive::kPrimChar:
374 case Primitive::kPrimShort:
375 case Primitive::kPrimNot:
376 case Primitive::kPrimInt:
377 Move32(location, instruction->GetLocations()->Out());
378 break;
379
380 case Primitive::kPrimLong:
381 Move64(location, instruction->GetLocations()->Out());
382 break;
383
384 default:
385 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
386 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000387 }
388}
389
390void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000391 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000392}
393
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000394void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000395 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000396 if (GetGraph()->GetExitBlock() == successor) {
397 codegen_->GenerateFrameExit();
398 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
399 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000400 }
401}
402
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000403void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000404 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000405}
406
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000407void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000408 if (kIsDebugBuild) {
409 __ Comment("Unreachable");
410 __ bkpt(0);
411 }
412}
413
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000414void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000415 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100416 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000417 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418}
419
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000420void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000421 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100422 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000423 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
424 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
425 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000426 }
427}
428
429void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000430 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100431 locations->SetInAt(0, Location::RequiresRegister());
432 locations->SetInAt(1, Location::RequiresRegister());
433 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000434 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000435}
436
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000437void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
438 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100439 __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
440 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
441 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
442 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000443}
444
445void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000446 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000447}
448
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000449void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
450 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000451}
452
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000453void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100454 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000455}
456
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000457void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100458 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000459}
460
461void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000462 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100463 switch (store->InputAt(1)->GetType()) {
464 case Primitive::kPrimBoolean:
465 case Primitive::kPrimByte:
466 case Primitive::kPrimChar:
467 case Primitive::kPrimShort:
468 case Primitive::kPrimInt:
469 case Primitive::kPrimNot:
470 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
471 break;
472
473 case Primitive::kPrimLong:
474 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
475 break;
476
477 default:
478 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
479 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000480 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000481}
482
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000483void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000484}
485
486void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100487 // TODO: Support constant locations.
488 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
489 locations->SetOut(Location::RequiresRegister());
490 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000491}
492
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000493void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000494 // Will be generated at use site.
495}
496
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100497void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100498 // TODO: Support constant locations.
499 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
500 locations->SetOut(Location::RequiresRegister());
501 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100502}
503
504void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
505 // Will be generated at use site.
506}
507
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000508void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000509 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000510}
511
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000512void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
513 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000514}
515
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000516void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000517 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100518 switch (ret->InputAt(0)->GetType()) {
519 case Primitive::kPrimBoolean:
520 case Primitive::kPrimByte:
521 case Primitive::kPrimChar:
522 case Primitive::kPrimShort:
523 case Primitive::kPrimInt:
524 case Primitive::kPrimNot:
525 locations->SetInAt(0, ArmCoreLocation(R0));
526 break;
527
528 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100529 locations->SetInAt(
530 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100531 break;
532
533 default:
534 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
535 }
536
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000537 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000538}
539
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000540void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100541 if (kIsDebugBuild) {
542 switch (ret->InputAt(0)->GetType()) {
543 case Primitive::kPrimBoolean:
544 case Primitive::kPrimByte:
545 case Primitive::kPrimChar:
546 case Primitive::kPrimShort:
547 case Primitive::kPrimInt:
548 case Primitive::kPrimNot:
549 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
550 break;
551
552 case Primitive::kPrimLong:
553 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
554 break;
555
556 default:
557 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
558 }
559 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000560 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000561}
562
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000563void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
564 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100565 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100566
567 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100568 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100569 HInstruction* input = invoke->InputAt(i);
570 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
571 }
572
573 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100574 case Primitive::kPrimBoolean:
575 case Primitive::kPrimByte:
576 case Primitive::kPrimChar:
577 case Primitive::kPrimShort:
578 case Primitive::kPrimInt:
579 case Primitive::kPrimNot:
580 locations->SetOut(ArmCoreLocation(R0));
581 break;
582
583 case Primitive::kPrimLong:
584 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
585 break;
586
587 case Primitive::kPrimVoid:
588 break;
589
590 case Primitive::kPrimDouble:
591 case Primitive::kPrimFloat:
592 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
593 break;
594 }
595
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000596 invoke->SetLocations(locations);
597}
598
599void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100600 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000601}
602
603void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100604 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000605 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100606 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000607
608 // TODO: Implement all kinds of calls:
609 // 1) boot -> boot
610 // 2) app -> boot
611 // 3) app -> app
612 //
613 // Currently we implement the app -> app logic, which looks up in the resolve cache.
614
615 // temp = method;
616 LoadCurrentMethod(temp);
617 // temp = temp->dex_cache_resolved_methods_;
618 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
619 // temp = temp[index_in_cache]
620 __ ldr(temp, Address(temp, index_in_cache));
621 // LR = temp[offset_of_quick_compiled_code]
622 __ ldr(LR, Address(temp,
623 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
624 // LR()
625 __ blx(LR);
626
627 codegen_->RecordPcInfo(invoke->GetDexPc());
628}
629
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000630void LocationsBuilderARM::VisitAdd(HAdd* add) {
631 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
632 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100633 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100634 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100635 locations->SetInAt(0, Location::RequiresRegister());
636 locations->SetInAt(1, Location::RequiresRegister());
637 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100638 break;
639 }
640
641 case Primitive::kPrimBoolean:
642 case Primitive::kPrimByte:
643 case Primitive::kPrimChar:
644 case Primitive::kPrimShort:
645 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
646 break;
647
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000648 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100649 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000650 }
651 add->SetLocations(locations);
652}
653
654void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
655 LocationSummary* locations = add->GetLocations();
656 switch (add->GetResultType()) {
657 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100658 __ add(locations->Out().AsArm().AsCoreRegister(),
659 locations->InAt(0).AsArm().AsCoreRegister(),
660 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000661 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100662
663 case Primitive::kPrimLong:
664 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
665 locations->InAt(0).AsArm().AsRegisterPairLow(),
666 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
667 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
668 locations->InAt(0).AsArm().AsRegisterPairHigh(),
669 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
670 break;
671
672 case Primitive::kPrimBoolean:
673 case Primitive::kPrimByte:
674 case Primitive::kPrimChar:
675 case Primitive::kPrimShort:
676 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
677 break;
678
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000679 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100680 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000681 }
682}
683
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100684void LocationsBuilderARM::VisitSub(HSub* sub) {
685 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
686 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100688 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100689 locations->SetInAt(0, Location::RequiresRegister());
690 locations->SetInAt(1, Location::RequiresRegister());
691 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100692 break;
693 }
694
695 case Primitive::kPrimBoolean:
696 case Primitive::kPrimByte:
697 case Primitive::kPrimChar:
698 case Primitive::kPrimShort:
699 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
700 break;
701
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100702 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100703 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100704 }
705 sub->SetLocations(locations);
706}
707
708void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
709 LocationSummary* locations = sub->GetLocations();
710 switch (sub->GetResultType()) {
711 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100712 __ sub(locations->Out().AsArm().AsCoreRegister(),
713 locations->InAt(0).AsArm().AsCoreRegister(),
714 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100715 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100716
717 case Primitive::kPrimLong:
718 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
719 locations->InAt(0).AsArm().AsRegisterPairLow(),
720 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
721 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
722 locations->InAt(0).AsArm().AsRegisterPairHigh(),
723 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
724 break;
725
726 case Primitive::kPrimBoolean:
727 case Primitive::kPrimByte:
728 case Primitive::kPrimChar:
729 case Primitive::kPrimShort:
730 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
731 break;
732
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100733 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100734 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100735 }
736}
737
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100738static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
739static constexpr size_t kRuntimeParameterCoreRegistersLength =
740 arraysize(kRuntimeParameterCoreRegisters);
741
742class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
743 public:
744 InvokeRuntimeCallingConvention()
745 : CallingConvention(kRuntimeParameterCoreRegisters,
746 kRuntimeParameterCoreRegistersLength) {}
747
748 private:
749 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
750};
751
752void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
753 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100754 InvokeRuntimeCallingConvention calling_convention;
755 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
756 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100757 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100758 instruction->SetLocations(locations);
759}
760
761void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
762 InvokeRuntimeCallingConvention calling_convention;
763 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
764 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
765
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100766 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100767 __ ldr(LR, Address(TR, offset));
768 __ blx(LR);
769
770 codegen_->RecordPcInfo(instruction->GetDexPc());
771}
772
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100773void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
774 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100775 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
776 if (location.IsStackSlot()) {
777 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
778 } else if (location.IsDoubleStackSlot()) {
779 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100780 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100781 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100782 instruction->SetLocations(locations);
783}
784
785void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100787}
788
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100789void LocationsBuilderARM::VisitNot(HNot* instruction) {
790 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100791 locations->SetInAt(0, Location::RequiresRegister());
792 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100793 instruction->SetLocations(locations);
794}
795
796void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
797 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100798 __ eor(locations->Out().AsArm().AsCoreRegister(),
799 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100800}
801
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100802void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100803 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
804 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
805 locations->SetInAt(i, Location::Any());
806 }
807 locations->SetOut(Location::Any());
808 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100809}
810
811void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
812 LOG(FATAL) << "Unimplemented";
813}
814
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100815void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
816 LOG(FATAL) << "Unimplemented";
817}
818
819void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
820 LOG(FATAL) << "Unimplemented";
821}
822
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000823} // namespace arm
824} // namespace art