blob: f1b16a1d4a4f1acb49b2d40486dce5bb053771fa [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 Geoffraya7aca372014-04-28 17:47:12 +010040CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
41 : CodeGenerator(graph, kNumberOfRegIds),
42 location_builder_(graph, this),
43 instruction_visitor_(graph, this) {}
44
45static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
46 return blocked_registers + kNumberOfAllocIds;
47}
48
49ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
50 bool* blocked_registers) const {
51 switch (type) {
52 case Primitive::kPrimLong: {
53 size_t reg = AllocateFreeRegisterInternal(
54 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
55 ArmManagedRegister pair =
56 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
57 blocked_registers[pair.AsRegisterPairLow()] = true;
58 blocked_registers[pair.AsRegisterPairHigh()] = true;
59 return pair;
60 }
61
62 case Primitive::kPrimByte:
63 case Primitive::kPrimBoolean:
64 case Primitive::kPrimChar:
65 case Primitive::kPrimShort:
66 case Primitive::kPrimInt:
67 case Primitive::kPrimNot: {
68 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
69 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
70 }
71
72 case Primitive::kPrimFloat:
73 case Primitive::kPrimDouble:
74 LOG(FATAL) << "Unimplemented register type " << type;
75
76 case Primitive::kPrimVoid:
77 LOG(FATAL) << "Unreachable type " << type;
78 }
79
80 return ManagedRegister::NoRegister();
81}
82
83void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
84 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
85
86 // Don't allocate the dalvik style register pair passing.
87 blocked_register_pairs[R1_R2] = true;
88
89 // Stack register, LR and PC are always reserved.
90 blocked_registers[SP] = true;
91 blocked_registers[LR] = true;
92 blocked_registers[PC] = true;
93
94 // Reserve R4 for suspend check.
95 blocked_registers[R4] = true;
96 blocked_register_pairs[R4_R5] = true;
97
98 // Reserve thread register.
99 blocked_registers[TR] = true;
100
101 // TODO: We currently don't use Quick's callee saved registers.
102 blocked_registers[R5] = true;
103 blocked_registers[R6] = true;
104 blocked_registers[R7] = true;
105 blocked_registers[R8] = true;
106 blocked_registers[R10] = true;
107 blocked_registers[R11] = true;
108 blocked_register_pairs[R6_R7] = true;
109}
110
111size_t CodeGeneratorARM::GetNumberOfRegisters() const {
112 return kNumberOfRegIds;
113}
114
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100115static Location ArmCoreLocation(Register reg) {
116 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
117}
118
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100119InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
120 : HGraphVisitor(graph),
121 assembler_(codegen->GetAssembler()),
122 codegen_(codegen) {}
123
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000124void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000125 core_spill_mask_ |= (1 << LR);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100126 __ PushList((1 << LR));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000127
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100128 SetFrameSize(RoundUp(
129 (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
130 + kVRegSize // filler
131 + kArmWordSize // Art method
132 + kNumberOfPushedRegistersAtEntry * kArmWordSize,
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100133 kStackAlignment));
134 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100135 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000136 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000137}
138
139void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100140 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100141 __ PopList((1 << PC));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000142}
143
144void CodeGeneratorARM::Bind(Label* label) {
145 __ Bind(label);
146}
147
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100148int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100149 uint16_t reg_number = local->GetRegNumber();
150 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
151 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
152 if (reg_number >= number_of_vregs - number_of_in_vregs) {
153 // Local is a parameter of the method. It is stored in the caller's frame.
154 return GetFrameSize() + kArmWordSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100155 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100156 } else {
157 // Local is a temporary in this method. It is stored in this method's frame.
158 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100159 - kVRegSize // filler.
160 - (number_of_vregs * kVRegSize)
161 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100162 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000163}
164
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100165Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
166 switch (load->GetType()) {
167 case Primitive::kPrimLong:
168 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
169 break;
170
171 case Primitive::kPrimInt:
172 case Primitive::kPrimNot:
173 return Location::StackSlot(GetStackSlot(load->GetLocal()));
174
175 case Primitive::kPrimFloat:
176 case Primitive::kPrimDouble:
177 LOG(FATAL) << "Unimplemented type " << load->GetType();
178
179 case Primitive::kPrimBoolean:
180 case Primitive::kPrimByte:
181 case Primitive::kPrimChar:
182 case Primitive::kPrimShort:
183 case Primitive::kPrimVoid:
184 LOG(FATAL) << "Unexpected type " << load->GetType();
185 }
186
187 LOG(FATAL) << "Unreachable";
188 return Location();
189}
190
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100191Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
192 switch (type) {
193 case Primitive::kPrimBoolean:
194 case Primitive::kPrimByte:
195 case Primitive::kPrimChar:
196 case Primitive::kPrimShort:
197 case Primitive::kPrimInt:
198 case Primitive::kPrimNot: {
199 uint32_t index = gp_index_++;
200 if (index < calling_convention.GetNumberOfRegisters()) {
201 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
202 } else {
203 return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100204 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100205 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100206
207 case Primitive::kPrimLong: {
208 uint32_t index = gp_index_;
209 gp_index_ += 2;
210 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
211 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
212 calling_convention.GetRegisterPairAt(index)));
213 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
214 return Location::QuickParameter(index);
215 } else {
216 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize));
217 }
218 }
219
220 case Primitive::kPrimDouble:
221 case Primitive::kPrimFloat:
222 LOG(FATAL) << "Unimplemented parameter type " << type;
223 break;
224
225 case Primitive::kPrimVoid:
226 LOG(FATAL) << "Unexpected parameter type " << type;
227 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100228 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100229 return Location();
230}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100231
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100232void CodeGeneratorARM::Move32(Location destination, Location source) {
233 if (source.Equals(destination)) {
234 return;
235 }
236 if (destination.IsRegister()) {
237 if (source.IsRegister()) {
238 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
239 } else {
240 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
241 }
242 } else {
243 DCHECK(destination.IsStackSlot());
244 if (source.IsRegister()) {
245 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
246 } else {
247 __ ldr(R0, Address(SP, source.GetStackIndex()));
248 __ str(R0, Address(SP, destination.GetStackIndex()));
249 }
250 }
251}
252
253void CodeGeneratorARM::Move64(Location destination, Location source) {
254 if (source.Equals(destination)) {
255 return;
256 }
257 if (destination.IsRegister()) {
258 if (source.IsRegister()) {
259 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
260 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
261 } else if (source.IsQuickParameter()) {
262 uint32_t argument_index = source.GetQuickParameterIndex();
263 InvokeDexCallingConvention calling_convention;
264 __ Mov(destination.AsArm().AsRegisterPairLow(),
265 calling_convention.GetRegisterAt(argument_index));
266 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100267 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100268 } else {
269 DCHECK(source.IsDoubleStackSlot());
270 if (destination.AsArm().AsRegisterPair() == R1_R2) {
271 __ ldr(R1, Address(SP, source.GetStackIndex()));
272 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
273 } else {
274 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
275 SP, source.GetStackIndex());
276 }
277 }
278 } else if (destination.IsQuickParameter()) {
279 InvokeDexCallingConvention calling_convention;
280 uint32_t argument_index = destination.GetQuickParameterIndex();
281 if (source.IsRegister()) {
282 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
283 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100284 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100285 } else {
286 DCHECK(source.IsDoubleStackSlot());
287 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
288 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100289 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100290 }
291 } else {
292 DCHECK(destination.IsDoubleStackSlot());
293 if (source.IsRegister()) {
294 if (source.AsArm().AsRegisterPair() == R1_R2) {
295 __ str(R1, Address(SP, destination.GetStackIndex()));
296 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
297 } else {
298 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
299 SP, destination.GetStackIndex());
300 }
301 } else if (source.IsQuickParameter()) {
302 InvokeDexCallingConvention calling_convention;
303 uint32_t argument_index = source.GetQuickParameterIndex();
304 __ str(calling_convention.GetRegisterAt(argument_index),
305 Address(SP, destination.GetStackIndex()));
306 __ ldr(R0,
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100307 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100308 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
309 } else {
310 DCHECK(source.IsDoubleStackSlot());
311 __ ldr(R0, Address(SP, source.GetStackIndex()));
312 __ str(R0, Address(SP, destination.GetStackIndex()));
313 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
314 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
315 }
316 }
317}
318
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100319void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
320 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100321 int32_t value = instruction->AsIntConstant()->GetValue();
322 if (location.IsRegister()) {
323 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
324 } else {
325 __ LoadImmediate(R0, value);
326 __ str(R0, Address(SP, location.GetStackIndex()));
327 }
328 } else if (instruction->AsLongConstant() != nullptr) {
329 int64_t value = instruction->AsLongConstant()->GetValue();
330 if (location.IsRegister()) {
331 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
332 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
333 } else {
334 __ LoadImmediate(R0, Low32Bits(value));
335 __ str(R0, Address(SP, location.GetStackIndex()));
336 __ LoadImmediate(R0, High32Bits(value));
337 __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize)));
338 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100339 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100340 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
341 switch (instruction->GetType()) {
342 case Primitive::kPrimBoolean:
343 case Primitive::kPrimByte:
344 case Primitive::kPrimChar:
345 case Primitive::kPrimShort:
346 case Primitive::kPrimInt:
347 case Primitive::kPrimNot:
348 Move32(location, Location::StackSlot(stack_slot));
349 break;
350
351 case Primitive::kPrimLong:
352 Move64(location, Location::DoubleStackSlot(stack_slot));
353 break;
354
355 default:
356 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
357 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000358 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100359 // This can currently only happen when the instruction that requests the move
360 // is the next to be compiled.
361 DCHECK_EQ(instruction->GetNext(), move_for);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100362 switch (instruction->GetType()) {
363 case Primitive::kPrimBoolean:
364 case Primitive::kPrimByte:
365 case Primitive::kPrimChar:
366 case Primitive::kPrimShort:
367 case Primitive::kPrimNot:
368 case Primitive::kPrimInt:
369 Move32(location, instruction->GetLocations()->Out());
370 break;
371
372 case Primitive::kPrimLong:
373 Move64(location, instruction->GetLocations()->Out());
374 break;
375
376 default:
377 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
378 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000379 }
380}
381
382void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000383 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000384}
385
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000386void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000387 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000388 if (GetGraph()->GetExitBlock() == successor) {
389 codegen_->GenerateFrameExit();
390 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
391 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000392 }
393}
394
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000395void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000396 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000397}
398
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000399void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000400 if (kIsDebugBuild) {
401 __ Comment("Unreachable");
402 __ bkpt(0);
403 }
404}
405
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000406void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000407 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100408 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000409 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000410}
411
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000412void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000413 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100414 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000415 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
416 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
417 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000418 }
419}
420
421void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000422 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100423 locations->SetInAt(0, Location::RequiresRegister());
424 locations->SetInAt(1, Location::RequiresRegister());
425 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000426 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000427}
428
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000429void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
430 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100431 __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
432 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
433 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
434 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000435}
436
437void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000438 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000439}
440
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000441void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
442 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000443}
444
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000445void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100446 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000447}
448
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000449void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100450 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000451}
452
453void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000454 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100455 switch (store->InputAt(1)->GetType()) {
456 case Primitive::kPrimBoolean:
457 case Primitive::kPrimByte:
458 case Primitive::kPrimChar:
459 case Primitive::kPrimShort:
460 case Primitive::kPrimInt:
461 case Primitive::kPrimNot:
462 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
463 break;
464
465 case Primitive::kPrimLong:
466 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
467 break;
468
469 default:
470 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
471 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000472 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000473}
474
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000475void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000476}
477
478void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000479 constant->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000480}
481
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000482void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000483 // Will be generated at use site.
484}
485
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100486void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
487 constant->SetLocations(nullptr);
488}
489
490void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
491 // Will be generated at use site.
492}
493
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000494void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000495 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000496}
497
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000498void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
499 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000500}
501
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000502void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000503 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100504 switch (ret->InputAt(0)->GetType()) {
505 case Primitive::kPrimBoolean:
506 case Primitive::kPrimByte:
507 case Primitive::kPrimChar:
508 case Primitive::kPrimShort:
509 case Primitive::kPrimInt:
510 case Primitive::kPrimNot:
511 locations->SetInAt(0, ArmCoreLocation(R0));
512 break;
513
514 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100515 locations->SetInAt(
516 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100517 break;
518
519 default:
520 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
521 }
522
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000523 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000524}
525
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000526void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100527 if (kIsDebugBuild) {
528 switch (ret->InputAt(0)->GetType()) {
529 case Primitive::kPrimBoolean:
530 case Primitive::kPrimByte:
531 case Primitive::kPrimChar:
532 case Primitive::kPrimShort:
533 case Primitive::kPrimInt:
534 case Primitive::kPrimNot:
535 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
536 break;
537
538 case Primitive::kPrimLong:
539 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
540 break;
541
542 default:
543 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
544 }
545 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000546 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000547}
548
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000549void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
550 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100551 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100552
553 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100554 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100555 HInstruction* input = invoke->InputAt(i);
556 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
557 }
558
559 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100560 case Primitive::kPrimBoolean:
561 case Primitive::kPrimByte:
562 case Primitive::kPrimChar:
563 case Primitive::kPrimShort:
564 case Primitive::kPrimInt:
565 case Primitive::kPrimNot:
566 locations->SetOut(ArmCoreLocation(R0));
567 break;
568
569 case Primitive::kPrimLong:
570 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
571 break;
572
573 case Primitive::kPrimVoid:
574 break;
575
576 case Primitive::kPrimDouble:
577 case Primitive::kPrimFloat:
578 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
579 break;
580 }
581
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000582 invoke->SetLocations(locations);
583}
584
585void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100586 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000587}
588
589void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100590 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000591 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100592 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000593
594 // TODO: Implement all kinds of calls:
595 // 1) boot -> boot
596 // 2) app -> boot
597 // 3) app -> app
598 //
599 // Currently we implement the app -> app logic, which looks up in the resolve cache.
600
601 // temp = method;
602 LoadCurrentMethod(temp);
603 // temp = temp->dex_cache_resolved_methods_;
604 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
605 // temp = temp[index_in_cache]
606 __ ldr(temp, Address(temp, index_in_cache));
607 // LR = temp[offset_of_quick_compiled_code]
608 __ ldr(LR, Address(temp,
609 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
610 // LR()
611 __ blx(LR);
612
613 codegen_->RecordPcInfo(invoke->GetDexPc());
614}
615
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000616void LocationsBuilderARM::VisitAdd(HAdd* add) {
617 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
618 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100619 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100620 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100621 locations->SetInAt(0, Location::RequiresRegister());
622 locations->SetInAt(1, Location::RequiresRegister());
623 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100624 break;
625 }
626
627 case Primitive::kPrimBoolean:
628 case Primitive::kPrimByte:
629 case Primitive::kPrimChar:
630 case Primitive::kPrimShort:
631 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
632 break;
633
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000634 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100635 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000636 }
637 add->SetLocations(locations);
638}
639
640void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
641 LocationSummary* locations = add->GetLocations();
642 switch (add->GetResultType()) {
643 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100644 __ add(locations->Out().AsArm().AsCoreRegister(),
645 locations->InAt(0).AsArm().AsCoreRegister(),
646 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000647 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100648
649 case Primitive::kPrimLong:
650 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
651 locations->InAt(0).AsArm().AsRegisterPairLow(),
652 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
653 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
654 locations->InAt(0).AsArm().AsRegisterPairHigh(),
655 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
656 break;
657
658 case Primitive::kPrimBoolean:
659 case Primitive::kPrimByte:
660 case Primitive::kPrimChar:
661 case Primitive::kPrimShort:
662 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
663 break;
664
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000665 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100666 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000667 }
668}
669
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100670void LocationsBuilderARM::VisitSub(HSub* sub) {
671 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
672 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100673 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100674 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100675 locations->SetInAt(0, Location::RequiresRegister());
676 locations->SetInAt(1, Location::RequiresRegister());
677 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100678 break;
679 }
680
681 case Primitive::kPrimBoolean:
682 case Primitive::kPrimByte:
683 case Primitive::kPrimChar:
684 case Primitive::kPrimShort:
685 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
686 break;
687
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100688 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100689 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100690 }
691 sub->SetLocations(locations);
692}
693
694void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
695 LocationSummary* locations = sub->GetLocations();
696 switch (sub->GetResultType()) {
697 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100698 __ sub(locations->Out().AsArm().AsCoreRegister(),
699 locations->InAt(0).AsArm().AsCoreRegister(),
700 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100701 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100702
703 case Primitive::kPrimLong:
704 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
705 locations->InAt(0).AsArm().AsRegisterPairLow(),
706 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
707 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
708 locations->InAt(0).AsArm().AsRegisterPairHigh(),
709 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
710 break;
711
712 case Primitive::kPrimBoolean:
713 case Primitive::kPrimByte:
714 case Primitive::kPrimChar:
715 case Primitive::kPrimShort:
716 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
717 break;
718
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100719 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100720 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100721 }
722}
723
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100724static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
725static constexpr size_t kRuntimeParameterCoreRegistersLength =
726 arraysize(kRuntimeParameterCoreRegisters);
727
728class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
729 public:
730 InvokeRuntimeCallingConvention()
731 : CallingConvention(kRuntimeParameterCoreRegisters,
732 kRuntimeParameterCoreRegistersLength) {}
733
734 private:
735 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
736};
737
738void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
739 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100740 InvokeRuntimeCallingConvention calling_convention;
741 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
742 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100743 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100744 instruction->SetLocations(locations);
745}
746
747void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
748 InvokeRuntimeCallingConvention calling_convention;
749 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
750 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
751
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100752 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100753 __ ldr(LR, Address(TR, offset));
754 __ blx(LR);
755
756 codegen_->RecordPcInfo(instruction->GetDexPc());
757}
758
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100759void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
760 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100761 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
762 if (location.IsStackSlot()) {
763 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
764 } else if (location.IsDoubleStackSlot()) {
765 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100766 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100767 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100768 instruction->SetLocations(locations);
769}
770
771void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100772 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100773}
774
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100775void LocationsBuilderARM::VisitNot(HNot* instruction) {
776 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100777 locations->SetInAt(0, Location::RequiresRegister());
778 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100779 instruction->SetLocations(locations);
780}
781
782void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
783 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100784 __ eor(locations->Out().AsArm().AsCoreRegister(),
785 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100786}
787
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100788void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
789 LOG(FATAL) << "Unimplemented";
790}
791
792void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
793 LOG(FATAL) << "Unimplemented";
794}
795
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100796void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
797 LOG(FATAL) << "Unimplemented";
798}
799
800void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
801 LOG(FATAL) << "Unimplemented";
802}
803
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000804} // namespace arm
805} // namespace art