blob: a446701b396d98cd33a1e2fa282087331943d630 [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 Geoffraya7aca372014-04-28 17:47:12 +010038CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
39 : CodeGenerator(graph, kNumberOfRegIds),
40 location_builder_(graph, this),
41 instruction_visitor_(graph, this) {}
42
43static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
44 return blocked_registers + kNumberOfAllocIds;
45}
46
47ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
48 bool* blocked_registers) const {
49 switch (type) {
50 case Primitive::kPrimLong: {
51 size_t reg = AllocateFreeRegisterInternal(
52 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
53 ArmManagedRegister pair =
54 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
55 blocked_registers[pair.AsRegisterPairLow()] = true;
56 blocked_registers[pair.AsRegisterPairHigh()] = true;
57 return pair;
58 }
59
60 case Primitive::kPrimByte:
61 case Primitive::kPrimBoolean:
62 case Primitive::kPrimChar:
63 case Primitive::kPrimShort:
64 case Primitive::kPrimInt:
65 case Primitive::kPrimNot: {
66 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
67 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
68 }
69
70 case Primitive::kPrimFloat:
71 case Primitive::kPrimDouble:
72 LOG(FATAL) << "Unimplemented register type " << type;
73
74 case Primitive::kPrimVoid:
75 LOG(FATAL) << "Unreachable type " << type;
76 }
77
78 return ManagedRegister::NoRegister();
79}
80
81void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
82 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
83
84 // Don't allocate the dalvik style register pair passing.
85 blocked_register_pairs[R1_R2] = true;
86
87 // Stack register, LR and PC are always reserved.
88 blocked_registers[SP] = true;
89 blocked_registers[LR] = true;
90 blocked_registers[PC] = true;
91
92 // Reserve R4 for suspend check.
93 blocked_registers[R4] = true;
94 blocked_register_pairs[R4_R5] = true;
95
96 // Reserve thread register.
97 blocked_registers[TR] = true;
98
99 // TODO: We currently don't use Quick's callee saved registers.
100 blocked_registers[R5] = true;
101 blocked_registers[R6] = true;
102 blocked_registers[R7] = true;
103 blocked_registers[R8] = true;
104 blocked_registers[R10] = true;
105 blocked_registers[R11] = true;
106 blocked_register_pairs[R6_R7] = true;
107}
108
109size_t CodeGeneratorARM::GetNumberOfRegisters() const {
110 return kNumberOfRegIds;
111}
112
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100113static Location ArmCoreLocation(Register reg) {
114 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
115}
116
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100117InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
118 : HGraphVisitor(graph),
119 assembler_(codegen->GetAssembler()),
120 codegen_(codegen) {}
121
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000122void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000123 core_spill_mask_ |= (1 << LR);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100124 __ PushList((1 << LR));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000125
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100126 SetFrameSize(RoundUp(
127 (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
128 + kVRegSize // filler
129 + kArmWordSize // Art method
130 + kNumberOfPushedRegistersAtEntry * kArmWordSize,
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100131 kStackAlignment));
132 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100133 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000134 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000135}
136
137void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100138 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100139 __ PopList((1 << PC));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000140}
141
142void CodeGeneratorARM::Bind(Label* label) {
143 __ Bind(label);
144}
145
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100146int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100147 uint16_t reg_number = local->GetRegNumber();
148 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
149 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
150 if (reg_number >= number_of_vregs - number_of_in_vregs) {
151 // Local is a parameter of the method. It is stored in the caller's frame.
152 return GetFrameSize() + kArmWordSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100153 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100154 } else {
155 // Local is a temporary in this method. It is stored in this method's frame.
156 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100157 - kVRegSize // filler.
158 - (number_of_vregs * kVRegSize)
159 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100160 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000161}
162
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100163Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
164 switch (load->GetType()) {
165 case Primitive::kPrimLong:
166 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
167 break;
168
169 case Primitive::kPrimInt:
170 case Primitive::kPrimNot:
171 return Location::StackSlot(GetStackSlot(load->GetLocal()));
172
173 case Primitive::kPrimFloat:
174 case Primitive::kPrimDouble:
175 LOG(FATAL) << "Unimplemented type " << load->GetType();
176
177 case Primitive::kPrimBoolean:
178 case Primitive::kPrimByte:
179 case Primitive::kPrimChar:
180 case Primitive::kPrimShort:
181 case Primitive::kPrimVoid:
182 LOG(FATAL) << "Unexpected type " << load->GetType();
183 }
184
185 LOG(FATAL) << "Unreachable";
186 return Location();
187}
188
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100189Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
190 switch (type) {
191 case Primitive::kPrimBoolean:
192 case Primitive::kPrimByte:
193 case Primitive::kPrimChar:
194 case Primitive::kPrimShort:
195 case Primitive::kPrimInt:
196 case Primitive::kPrimNot: {
197 uint32_t index = gp_index_++;
198 if (index < calling_convention.GetNumberOfRegisters()) {
199 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
200 } else {
201 return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100202 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100203 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100204
205 case Primitive::kPrimLong: {
206 uint32_t index = gp_index_;
207 gp_index_ += 2;
208 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
209 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
210 calling_convention.GetRegisterPairAt(index)));
211 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
212 return Location::QuickParameter(index);
213 } else {
214 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
215 }
216 }
217
218 case Primitive::kPrimDouble:
219 case Primitive::kPrimFloat:
220 LOG(FATAL) << "Unimplemented parameter type " << type;
221 break;
222
223 case Primitive::kPrimVoid:
224 LOG(FATAL) << "Unexpected parameter type " << type;
225 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100226 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100227 return Location();
228}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100229
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100230void CodeGeneratorARM::Move32(Location destination, Location source) {
231 if (source.Equals(destination)) {
232 return;
233 }
234 if (destination.IsRegister()) {
235 if (source.IsRegister()) {
236 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
237 } else {
238 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
239 }
240 } else {
241 DCHECK(destination.IsStackSlot());
242 if (source.IsRegister()) {
243 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
244 } else {
245 __ ldr(R0, Address(SP, source.GetStackIndex()));
246 __ str(R0, Address(SP, destination.GetStackIndex()));
247 }
248 }
249}
250
251void CodeGeneratorARM::Move64(Location destination, Location source) {
252 if (source.Equals(destination)) {
253 return;
254 }
255 if (destination.IsRegister()) {
256 if (source.IsRegister()) {
257 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
258 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
259 } else if (source.IsQuickParameter()) {
260 uint32_t argument_index = source.GetQuickParameterIndex();
261 InvokeDexCallingConvention calling_convention;
262 __ Mov(destination.AsArm().AsRegisterPairLow(),
263 calling_convention.GetRegisterAt(argument_index));
264 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100265 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100266 } else {
267 DCHECK(source.IsDoubleStackSlot());
268 if (destination.AsArm().AsRegisterPair() == R1_R2) {
269 __ ldr(R1, Address(SP, source.GetStackIndex()));
270 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
271 } else {
272 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
273 SP, source.GetStackIndex());
274 }
275 }
276 } else if (destination.IsQuickParameter()) {
277 InvokeDexCallingConvention calling_convention;
278 uint32_t argument_index = destination.GetQuickParameterIndex();
279 if (source.IsRegister()) {
280 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
281 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100282 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100283 } else {
284 DCHECK(source.IsDoubleStackSlot());
285 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
286 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100287 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100288 }
289 } else {
290 DCHECK(destination.IsDoubleStackSlot());
291 if (source.IsRegister()) {
292 if (source.AsArm().AsRegisterPair() == R1_R2) {
293 __ str(R1, Address(SP, destination.GetStackIndex()));
294 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
295 } else {
296 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
297 SP, destination.GetStackIndex());
298 }
299 } else if (source.IsQuickParameter()) {
300 InvokeDexCallingConvention calling_convention;
301 uint32_t argument_index = source.GetQuickParameterIndex();
302 __ str(calling_convention.GetRegisterAt(argument_index),
303 Address(SP, destination.GetStackIndex()));
304 __ ldr(R0,
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100305 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100306 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
307 } else {
308 DCHECK(source.IsDoubleStackSlot());
309 __ ldr(R0, Address(SP, source.GetStackIndex()));
310 __ str(R0, Address(SP, destination.GetStackIndex()));
311 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
312 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
313 }
314 }
315}
316
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100317void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
318 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100319 int32_t value = instruction->AsIntConstant()->GetValue();
320 if (location.IsRegister()) {
321 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
322 } else {
323 __ LoadImmediate(R0, value);
324 __ str(R0, Address(SP, location.GetStackIndex()));
325 }
326 } else if (instruction->AsLongConstant() != nullptr) {
327 int64_t value = instruction->AsLongConstant()->GetValue();
328 if (location.IsRegister()) {
329 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
330 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
331 } else {
332 __ LoadImmediate(R0, Low32Bits(value));
333 __ str(R0, Address(SP, location.GetStackIndex()));
334 __ LoadImmediate(R0, High32Bits(value));
335 __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize)));
336 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100337 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100338 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
339 switch (instruction->GetType()) {
340 case Primitive::kPrimBoolean:
341 case Primitive::kPrimByte:
342 case Primitive::kPrimChar:
343 case Primitive::kPrimShort:
344 case Primitive::kPrimInt:
345 case Primitive::kPrimNot:
346 Move32(location, Location::StackSlot(stack_slot));
347 break;
348
349 case Primitive::kPrimLong:
350 Move64(location, Location::DoubleStackSlot(stack_slot));
351 break;
352
353 default:
354 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
355 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000356 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100357 // This can currently only happen when the instruction that requests the move
358 // is the next to be compiled.
359 DCHECK_EQ(instruction->GetNext(), move_for);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100360 switch (instruction->GetType()) {
361 case Primitive::kPrimBoolean:
362 case Primitive::kPrimByte:
363 case Primitive::kPrimChar:
364 case Primitive::kPrimShort:
365 case Primitive::kPrimNot:
366 case Primitive::kPrimInt:
367 Move32(location, instruction->GetLocations()->Out());
368 break;
369
370 case Primitive::kPrimLong:
371 Move64(location, instruction->GetLocations()->Out());
372 break;
373
374 default:
375 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
376 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000377 }
378}
379
380void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000381 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000382}
383
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000384void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000385 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000386 if (GetGraph()->GetExitBlock() == successor) {
387 codegen_->GenerateFrameExit();
388 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
389 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000390 }
391}
392
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000393void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000394 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000395}
396
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000397void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000398 if (kIsDebugBuild) {
399 __ Comment("Unreachable");
400 __ bkpt(0);
401 }
402}
403
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000404void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000405 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100406 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000407 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000408}
409
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000410void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000411 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100412 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000413 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
414 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
415 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000416 }
417}
418
419void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000420 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100421 locations->SetInAt(0, Location::RequiresRegister());
422 locations->SetInAt(1, Location::RequiresRegister());
423 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000424 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000425}
426
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000427void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
428 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100429 __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
430 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
431 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
432 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000433}
434
435void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000436 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000437}
438
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000439void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
440 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000441}
442
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000443void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100444 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000445}
446
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000447void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100448 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000449}
450
451void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000452 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100453 switch (store->InputAt(1)->GetType()) {
454 case Primitive::kPrimBoolean:
455 case Primitive::kPrimByte:
456 case Primitive::kPrimChar:
457 case Primitive::kPrimShort:
458 case Primitive::kPrimInt:
459 case Primitive::kPrimNot:
460 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
461 break;
462
463 case Primitive::kPrimLong:
464 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
465 break;
466
467 default:
468 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
469 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000470 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000471}
472
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000473void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000474}
475
476void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000477 constant->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000478}
479
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000480void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000481 // Will be generated at use site.
482}
483
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100484void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
485 constant->SetLocations(nullptr);
486}
487
488void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
489 // Will be generated at use site.
490}
491
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000492void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000493 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000494}
495
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000496void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
497 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000498}
499
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000500void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000501 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100502 switch (ret->InputAt(0)->GetType()) {
503 case Primitive::kPrimBoolean:
504 case Primitive::kPrimByte:
505 case Primitive::kPrimChar:
506 case Primitive::kPrimShort:
507 case Primitive::kPrimInt:
508 case Primitive::kPrimNot:
509 locations->SetInAt(0, ArmCoreLocation(R0));
510 break;
511
512 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100513 locations->SetInAt(
514 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100515 break;
516
517 default:
518 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
519 }
520
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000521 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000522}
523
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000524void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100525 if (kIsDebugBuild) {
526 switch (ret->InputAt(0)->GetType()) {
527 case Primitive::kPrimBoolean:
528 case Primitive::kPrimByte:
529 case Primitive::kPrimChar:
530 case Primitive::kPrimShort:
531 case Primitive::kPrimInt:
532 case Primitive::kPrimNot:
533 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
534 break;
535
536 case Primitive::kPrimLong:
537 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
538 break;
539
540 default:
541 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
542 }
543 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000544 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000545}
546
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000547void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
548 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100549 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100550
551 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100552 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100553 HInstruction* input = invoke->InputAt(i);
554 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
555 }
556
557 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100558 case Primitive::kPrimBoolean:
559 case Primitive::kPrimByte:
560 case Primitive::kPrimChar:
561 case Primitive::kPrimShort:
562 case Primitive::kPrimInt:
563 case Primitive::kPrimNot:
564 locations->SetOut(ArmCoreLocation(R0));
565 break;
566
567 case Primitive::kPrimLong:
568 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
569 break;
570
571 case Primitive::kPrimVoid:
572 break;
573
574 case Primitive::kPrimDouble:
575 case Primitive::kPrimFloat:
576 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
577 break;
578 }
579
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000580 invoke->SetLocations(locations);
581}
582
583void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100584 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000585}
586
587void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100588 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000589 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100590 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000591
592 // TODO: Implement all kinds of calls:
593 // 1) boot -> boot
594 // 2) app -> boot
595 // 3) app -> app
596 //
597 // Currently we implement the app -> app logic, which looks up in the resolve cache.
598
599 // temp = method;
600 LoadCurrentMethod(temp);
601 // temp = temp->dex_cache_resolved_methods_;
602 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
603 // temp = temp[index_in_cache]
604 __ ldr(temp, Address(temp, index_in_cache));
605 // LR = temp[offset_of_quick_compiled_code]
606 __ ldr(LR, Address(temp,
607 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
608 // LR()
609 __ blx(LR);
610
611 codegen_->RecordPcInfo(invoke->GetDexPc());
612}
613
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000614void LocationsBuilderARM::VisitAdd(HAdd* add) {
615 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
616 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100617 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100618 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100619 locations->SetInAt(0, Location::RequiresRegister());
620 locations->SetInAt(1, Location::RequiresRegister());
621 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100622 break;
623 }
624
625 case Primitive::kPrimBoolean:
626 case Primitive::kPrimByte:
627 case Primitive::kPrimChar:
628 case Primitive::kPrimShort:
629 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
630 break;
631
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000632 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100633 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000634 }
635 add->SetLocations(locations);
636}
637
638void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
639 LocationSummary* locations = add->GetLocations();
640 switch (add->GetResultType()) {
641 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642 __ add(locations->Out().AsArm().AsCoreRegister(),
643 locations->InAt(0).AsArm().AsCoreRegister(),
644 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000645 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100646
647 case Primitive::kPrimLong:
648 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
649 locations->InAt(0).AsArm().AsRegisterPairLow(),
650 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
651 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
652 locations->InAt(0).AsArm().AsRegisterPairHigh(),
653 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
654 break;
655
656 case Primitive::kPrimBoolean:
657 case Primitive::kPrimByte:
658 case Primitive::kPrimChar:
659 case Primitive::kPrimShort:
660 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
661 break;
662
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000663 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000665 }
666}
667
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100668void LocationsBuilderARM::VisitSub(HSub* sub) {
669 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
670 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100671 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100672 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100673 locations->SetInAt(0, Location::RequiresRegister());
674 locations->SetInAt(1, Location::RequiresRegister());
675 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100676 break;
677 }
678
679 case Primitive::kPrimBoolean:
680 case Primitive::kPrimByte:
681 case Primitive::kPrimChar:
682 case Primitive::kPrimShort:
683 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
684 break;
685
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100686 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100687 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100688 }
689 sub->SetLocations(locations);
690}
691
692void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
693 LocationSummary* locations = sub->GetLocations();
694 switch (sub->GetResultType()) {
695 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100696 __ sub(locations->Out().AsArm().AsCoreRegister(),
697 locations->InAt(0).AsArm().AsCoreRegister(),
698 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100699 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100700
701 case Primitive::kPrimLong:
702 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
703 locations->InAt(0).AsArm().AsRegisterPairLow(),
704 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
705 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
706 locations->InAt(0).AsArm().AsRegisterPairHigh(),
707 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
708 break;
709
710 case Primitive::kPrimBoolean:
711 case Primitive::kPrimByte:
712 case Primitive::kPrimChar:
713 case Primitive::kPrimShort:
714 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
715 break;
716
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100717 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100718 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100719 }
720}
721
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100722static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
723static constexpr size_t kRuntimeParameterCoreRegistersLength =
724 arraysize(kRuntimeParameterCoreRegisters);
725
726class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
727 public:
728 InvokeRuntimeCallingConvention()
729 : CallingConvention(kRuntimeParameterCoreRegisters,
730 kRuntimeParameterCoreRegistersLength) {}
731
732 private:
733 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
734};
735
736void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
737 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100738 InvokeRuntimeCallingConvention calling_convention;
739 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
740 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100742 instruction->SetLocations(locations);
743}
744
745void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
746 InvokeRuntimeCallingConvention calling_convention;
747 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
748 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
749
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100750 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100751 __ ldr(LR, Address(TR, offset));
752 __ blx(LR);
753
754 codegen_->RecordPcInfo(instruction->GetDexPc());
755}
756
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100757void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
758 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100759 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
760 if (location.IsStackSlot()) {
761 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
762 } else if (location.IsDoubleStackSlot()) {
763 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100764 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100765 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100766 instruction->SetLocations(locations);
767}
768
769void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100770 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100771}
772
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100773void LocationsBuilderARM::VisitNot(HNot* instruction) {
774 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100775 locations->SetInAt(0, Location::RequiresRegister());
776 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100777 instruction->SetLocations(locations);
778}
779
780void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
781 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100782 __ eor(locations->Out().AsArm().AsCoreRegister(),
783 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100784}
785
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100786void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
787 LOG(FATAL) << "Unimplemented";
788}
789
790void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
791 LOG(FATAL) << "Unimplemented";
792}
793
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000794} // namespace arm
795} // namespace art