blob: 212a6dc37021e8b731d75fab89804d9b249f85f5 [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"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070019#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000020#include "mirror/array.h"
21#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070022#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010023#include "utils/assembler.h"
24#include "utils/arm/assembler_arm.h"
25#include "utils/arm/managed_register_arm.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),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +010051 instruction_visitor_(graph, this),
52 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +010053
54static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
55 return blocked_registers + kNumberOfAllocIds;
56}
57
58ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
59 bool* blocked_registers) const {
60 switch (type) {
61 case Primitive::kPrimLong: {
62 size_t reg = AllocateFreeRegisterInternal(
63 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
64 ArmManagedRegister pair =
65 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
66 blocked_registers[pair.AsRegisterPairLow()] = true;
67 blocked_registers[pair.AsRegisterPairHigh()] = true;
68 return pair;
69 }
70
71 case Primitive::kPrimByte:
72 case Primitive::kPrimBoolean:
73 case Primitive::kPrimChar:
74 case Primitive::kPrimShort:
75 case Primitive::kPrimInt:
76 case Primitive::kPrimNot: {
77 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
78 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
79 }
80
81 case Primitive::kPrimFloat:
82 case Primitive::kPrimDouble:
83 LOG(FATAL) << "Unimplemented register type " << type;
84
85 case Primitive::kPrimVoid:
86 LOG(FATAL) << "Unreachable type " << type;
87 }
88
89 return ManagedRegister::NoRegister();
90}
91
92void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
93 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
94
95 // Don't allocate the dalvik style register pair passing.
96 blocked_register_pairs[R1_R2] = true;
97
98 // Stack register, LR and PC are always reserved.
99 blocked_registers[SP] = true;
100 blocked_registers[LR] = true;
101 blocked_registers[PC] = true;
102
103 // Reserve R4 for suspend check.
104 blocked_registers[R4] = true;
105 blocked_register_pairs[R4_R5] = true;
106
107 // Reserve thread register.
108 blocked_registers[TR] = true;
109
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100110 // Reserve temp register.
111 blocked_registers[IP] = true;
112
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100113 // TODO: We currently don't use Quick's callee saved registers.
114 blocked_registers[R5] = true;
115 blocked_registers[R6] = true;
116 blocked_registers[R7] = true;
117 blocked_registers[R8] = true;
118 blocked_registers[R10] = true;
119 blocked_registers[R11] = true;
120 blocked_register_pairs[R6_R7] = true;
121}
122
123size_t CodeGeneratorARM::GetNumberOfRegisters() const {
124 return kNumberOfRegIds;
125}
126
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100127static Location ArmCoreLocation(Register reg) {
128 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
129}
130
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100131InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
132 : HGraphVisitor(graph),
133 assembler_(codegen->GetAssembler()),
134 codegen_(codegen) {}
135
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100136void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) {
137 SetFrameSize(RoundUp(
138 number_of_spill_slots * kVRegSize
139 + kVRegSize // Art method
140 + kNumberOfPushedRegistersAtEntry * kArmWordSize,
141 kStackAlignment));
142}
143
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000144void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000145 core_spill_mask_ |= (1 << LR);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100146 __ PushList((1 << LR));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000147
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100148 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100149 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000150 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000151}
152
153void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100154 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100155 __ PopList((1 << PC));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000156}
157
158void CodeGeneratorARM::Bind(Label* label) {
159 __ Bind(label);
160}
161
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100162int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100163 uint16_t reg_number = local->GetRegNumber();
164 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
165 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
166 if (reg_number >= number_of_vregs - number_of_in_vregs) {
167 // Local is a parameter of the method. It is stored in the caller's frame.
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100168 return GetFrameSize() + kVRegSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100169 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100170 } else {
171 // Local is a temporary in this method. It is stored in this method's frame.
172 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100173 - kVRegSize // filler.
174 - (number_of_vregs * kVRegSize)
175 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100176 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000177}
178
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100179Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
180 switch (load->GetType()) {
181 case Primitive::kPrimLong:
182 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
183 break;
184
185 case Primitive::kPrimInt:
186 case Primitive::kPrimNot:
187 return Location::StackSlot(GetStackSlot(load->GetLocal()));
188
189 case Primitive::kPrimFloat:
190 case Primitive::kPrimDouble:
191 LOG(FATAL) << "Unimplemented type " << load->GetType();
192
193 case Primitive::kPrimBoolean:
194 case Primitive::kPrimByte:
195 case Primitive::kPrimChar:
196 case Primitive::kPrimShort:
197 case Primitive::kPrimVoid:
198 LOG(FATAL) << "Unexpected type " << load->GetType();
199 }
200
201 LOG(FATAL) << "Unreachable";
202 return Location();
203}
204
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100205Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
206 switch (type) {
207 case Primitive::kPrimBoolean:
208 case Primitive::kPrimByte:
209 case Primitive::kPrimChar:
210 case Primitive::kPrimShort:
211 case Primitive::kPrimInt:
212 case Primitive::kPrimNot: {
213 uint32_t index = gp_index_++;
214 if (index < calling_convention.GetNumberOfRegisters()) {
215 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
216 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100217 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100218 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100219 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100220
221 case Primitive::kPrimLong: {
222 uint32_t index = gp_index_;
223 gp_index_ += 2;
224 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
225 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
226 calling_convention.GetRegisterPairAt(index)));
227 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
228 return Location::QuickParameter(index);
229 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100230 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100231 }
232 }
233
234 case Primitive::kPrimDouble:
235 case Primitive::kPrimFloat:
236 LOG(FATAL) << "Unimplemented parameter type " << type;
237 break;
238
239 case Primitive::kPrimVoid:
240 LOG(FATAL) << "Unexpected parameter type " << type;
241 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100242 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100243 return Location();
244}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100245
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100246void CodeGeneratorARM::Move32(Location destination, Location source) {
247 if (source.Equals(destination)) {
248 return;
249 }
250 if (destination.IsRegister()) {
251 if (source.IsRegister()) {
252 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
253 } else {
254 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
255 }
256 } else {
257 DCHECK(destination.IsStackSlot());
258 if (source.IsRegister()) {
259 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
260 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100261 __ ldr(IP, Address(SP, source.GetStackIndex()));
262 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100263 }
264 }
265}
266
267void CodeGeneratorARM::Move64(Location destination, Location source) {
268 if (source.Equals(destination)) {
269 return;
270 }
271 if (destination.IsRegister()) {
272 if (source.IsRegister()) {
273 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
274 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
275 } else if (source.IsQuickParameter()) {
276 uint32_t argument_index = source.GetQuickParameterIndex();
277 InvokeDexCallingConvention calling_convention;
278 __ Mov(destination.AsArm().AsRegisterPairLow(),
279 calling_convention.GetRegisterAt(argument_index));
280 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100281 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100282 } else {
283 DCHECK(source.IsDoubleStackSlot());
284 if (destination.AsArm().AsRegisterPair() == R1_R2) {
285 __ ldr(R1, Address(SP, source.GetStackIndex()));
286 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
287 } else {
288 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
289 SP, source.GetStackIndex());
290 }
291 }
292 } else if (destination.IsQuickParameter()) {
293 InvokeDexCallingConvention calling_convention;
294 uint32_t argument_index = destination.GetQuickParameterIndex();
295 if (source.IsRegister()) {
296 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
297 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100298 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100299 } else {
300 DCHECK(source.IsDoubleStackSlot());
301 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100302 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
303 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100304 }
305 } else {
306 DCHECK(destination.IsDoubleStackSlot());
307 if (source.IsRegister()) {
308 if (source.AsArm().AsRegisterPair() == R1_R2) {
309 __ str(R1, Address(SP, destination.GetStackIndex()));
310 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
311 } else {
312 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
313 SP, destination.GetStackIndex());
314 }
315 } else if (source.IsQuickParameter()) {
316 InvokeDexCallingConvention calling_convention;
317 uint32_t argument_index = source.GetQuickParameterIndex();
318 __ str(calling_convention.GetRegisterAt(argument_index),
319 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100320 __ ldr(R0,
321 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
322 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100323 } else {
324 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100325 __ ldr(IP, Address(SP, source.GetStackIndex()));
326 __ str(IP, Address(SP, destination.GetStackIndex()));
327 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
328 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100329 }
330 }
331}
332
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100333void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
334 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100335 int32_t value = instruction->AsIntConstant()->GetValue();
336 if (location.IsRegister()) {
337 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
338 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100339 __ LoadImmediate(IP, value);
340 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100341 }
342 } else if (instruction->AsLongConstant() != nullptr) {
343 int64_t value = instruction->AsLongConstant()->GetValue();
344 if (location.IsRegister()) {
345 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
346 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
347 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100348 __ LoadImmediate(IP, Low32Bits(value));
349 __ str(IP, Address(SP, location.GetStackIndex()));
350 __ LoadImmediate(IP, High32Bits(value));
351 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100352 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100353 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100354 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
355 switch (instruction->GetType()) {
356 case Primitive::kPrimBoolean:
357 case Primitive::kPrimByte:
358 case Primitive::kPrimChar:
359 case Primitive::kPrimShort:
360 case Primitive::kPrimInt:
361 case Primitive::kPrimNot:
362 Move32(location, Location::StackSlot(stack_slot));
363 break;
364
365 case Primitive::kPrimLong:
366 Move64(location, Location::DoubleStackSlot(stack_slot));
367 break;
368
369 default:
370 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
371 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000372 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100373 // This can currently only happen when the instruction that requests the move
374 // is the next to be compiled.
375 DCHECK_EQ(instruction->GetNext(), move_for);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100376 switch (instruction->GetType()) {
377 case Primitive::kPrimBoolean:
378 case Primitive::kPrimByte:
379 case Primitive::kPrimChar:
380 case Primitive::kPrimShort:
381 case Primitive::kPrimNot:
382 case Primitive::kPrimInt:
383 Move32(location, instruction->GetLocations()->Out());
384 break;
385
386 case Primitive::kPrimLong:
387 Move64(location, instruction->GetLocations()->Out());
388 break;
389
390 default:
391 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
392 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000393 }
394}
395
396void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000397 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000398}
399
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000400void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000401 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000402 if (GetGraph()->GetExitBlock() == successor) {
403 codegen_->GenerateFrameExit();
404 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
405 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000406 }
407}
408
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000409void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000410 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000411}
412
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000413void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000414 if (kIsDebugBuild) {
415 __ Comment("Unreachable");
416 __ bkpt(0);
417 }
418}
419
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000420void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000421 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100422 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000423 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000424}
425
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000426void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000427 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100428 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000429 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
430 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
431 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000432 }
433}
434
435void LocationsBuilderARM::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000436 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100437 locations->SetInAt(0, Location::RequiresRegister());
438 locations->SetInAt(1, Location::RequiresRegister());
439 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000440 equal->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000441}
442
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000443void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
444 LocationSummary* locations = equal->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100445 __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
446 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
447 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
448 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000449}
450
451void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000452 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000453}
454
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000455void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
456 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000457}
458
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000459void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100460 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000461}
462
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000463void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100464 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000465}
466
467void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000468 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100469 switch (store->InputAt(1)->GetType()) {
470 case Primitive::kPrimBoolean:
471 case Primitive::kPrimByte:
472 case Primitive::kPrimChar:
473 case Primitive::kPrimShort:
474 case Primitive::kPrimInt:
475 case Primitive::kPrimNot:
476 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
477 break;
478
479 case Primitive::kPrimLong:
480 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
481 break;
482
483 default:
484 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
485 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000486 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000487}
488
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000489void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000490}
491
492void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100493 // TODO: Support constant locations.
494 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
495 locations->SetOut(Location::RequiresRegister());
496 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000497}
498
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000499void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100500 codegen_->Move(constant, constant->GetLocations()->Out(), nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000501}
502
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100503void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100504 // TODO: Support constant locations.
505 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
506 locations->SetOut(Location::RequiresRegister());
507 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100508}
509
510void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
511 // Will be generated at use site.
512}
513
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000514void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000515 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000516}
517
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000518void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
519 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000520}
521
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000522void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000523 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100524 switch (ret->InputAt(0)->GetType()) {
525 case Primitive::kPrimBoolean:
526 case Primitive::kPrimByte:
527 case Primitive::kPrimChar:
528 case Primitive::kPrimShort:
529 case Primitive::kPrimInt:
530 case Primitive::kPrimNot:
531 locations->SetInAt(0, ArmCoreLocation(R0));
532 break;
533
534 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100535 locations->SetInAt(
536 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100537 break;
538
539 default:
540 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
541 }
542
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000543 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000544}
545
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000546void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100547 if (kIsDebugBuild) {
548 switch (ret->InputAt(0)->GetType()) {
549 case Primitive::kPrimBoolean:
550 case Primitive::kPrimByte:
551 case Primitive::kPrimChar:
552 case Primitive::kPrimShort:
553 case Primitive::kPrimInt:
554 case Primitive::kPrimNot:
555 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
556 break;
557
558 case Primitive::kPrimLong:
559 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
560 break;
561
562 default:
563 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
564 }
565 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000566 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000567}
568
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000569void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
570 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100571 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100572
573 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100574 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100575 HInstruction* input = invoke->InputAt(i);
576 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
577 }
578
579 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100580 case Primitive::kPrimBoolean:
581 case Primitive::kPrimByte:
582 case Primitive::kPrimChar:
583 case Primitive::kPrimShort:
584 case Primitive::kPrimInt:
585 case Primitive::kPrimNot:
586 locations->SetOut(ArmCoreLocation(R0));
587 break;
588
589 case Primitive::kPrimLong:
590 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
591 break;
592
593 case Primitive::kPrimVoid:
594 break;
595
596 case Primitive::kPrimDouble:
597 case Primitive::kPrimFloat:
598 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
599 break;
600 }
601
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000602 invoke->SetLocations(locations);
603}
604
605void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100606 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000607}
608
609void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100610 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000611 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100612 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000613
614 // TODO: Implement all kinds of calls:
615 // 1) boot -> boot
616 // 2) app -> boot
617 // 3) app -> app
618 //
619 // Currently we implement the app -> app logic, which looks up in the resolve cache.
620
621 // temp = method;
622 LoadCurrentMethod(temp);
623 // temp = temp->dex_cache_resolved_methods_;
624 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
625 // temp = temp[index_in_cache]
626 __ ldr(temp, Address(temp, index_in_cache));
627 // LR = temp[offset_of_quick_compiled_code]
628 __ ldr(LR, Address(temp,
629 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
630 // LR()
631 __ blx(LR);
632
633 codegen_->RecordPcInfo(invoke->GetDexPc());
634}
635
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000636void LocationsBuilderARM::VisitAdd(HAdd* add) {
637 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
638 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100639 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100640 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100641 locations->SetInAt(0, Location::RequiresRegister());
642 locations->SetInAt(1, Location::RequiresRegister());
643 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100644 break;
645 }
646
647 case Primitive::kPrimBoolean:
648 case Primitive::kPrimByte:
649 case Primitive::kPrimChar:
650 case Primitive::kPrimShort:
651 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
652 break;
653
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000654 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100655 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000656 }
657 add->SetLocations(locations);
658}
659
660void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
661 LocationSummary* locations = add->GetLocations();
662 switch (add->GetResultType()) {
663 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 __ add(locations->Out().AsArm().AsCoreRegister(),
665 locations->InAt(0).AsArm().AsCoreRegister(),
666 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000667 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100668
669 case Primitive::kPrimLong:
670 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
671 locations->InAt(0).AsArm().AsRegisterPairLow(),
672 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
673 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
674 locations->InAt(0).AsArm().AsRegisterPairHigh(),
675 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
676 break;
677
678 case Primitive::kPrimBoolean:
679 case Primitive::kPrimByte:
680 case Primitive::kPrimChar:
681 case Primitive::kPrimShort:
682 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
683 break;
684
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000685 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100686 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000687 }
688}
689
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100690void LocationsBuilderARM::VisitSub(HSub* sub) {
691 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
692 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100693 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100694 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100695 locations->SetInAt(0, Location::RequiresRegister());
696 locations->SetInAt(1, Location::RequiresRegister());
697 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100698 break;
699 }
700
701 case Primitive::kPrimBoolean:
702 case Primitive::kPrimByte:
703 case Primitive::kPrimChar:
704 case Primitive::kPrimShort:
705 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
706 break;
707
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100708 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100709 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100710 }
711 sub->SetLocations(locations);
712}
713
714void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
715 LocationSummary* locations = sub->GetLocations();
716 switch (sub->GetResultType()) {
717 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100718 __ sub(locations->Out().AsArm().AsCoreRegister(),
719 locations->InAt(0).AsArm().AsCoreRegister(),
720 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100721 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100722
723 case Primitive::kPrimLong:
724 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
725 locations->InAt(0).AsArm().AsRegisterPairLow(),
726 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
727 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
728 locations->InAt(0).AsArm().AsRegisterPairHigh(),
729 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
730 break;
731
732 case Primitive::kPrimBoolean:
733 case Primitive::kPrimByte:
734 case Primitive::kPrimChar:
735 case Primitive::kPrimShort:
736 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
737 break;
738
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100739 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100740 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100741 }
742}
743
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100744static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
745static constexpr size_t kRuntimeParameterCoreRegistersLength =
746 arraysize(kRuntimeParameterCoreRegisters);
747
748class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
749 public:
750 InvokeRuntimeCallingConvention()
751 : CallingConvention(kRuntimeParameterCoreRegisters,
752 kRuntimeParameterCoreRegistersLength) {}
753
754 private:
755 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
756};
757
758void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
759 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100760 InvokeRuntimeCallingConvention calling_convention;
761 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
762 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100763 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100764 instruction->SetLocations(locations);
765}
766
767void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
768 InvokeRuntimeCallingConvention calling_convention;
769 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
770 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
771
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100772 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100773 __ ldr(LR, Address(TR, offset));
774 __ blx(LR);
775
776 codegen_->RecordPcInfo(instruction->GetDexPc());
777}
778
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100779void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
780 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100781 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
782 if (location.IsStackSlot()) {
783 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
784 } else if (location.IsDoubleStackSlot()) {
785 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100786 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100787 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100788 instruction->SetLocations(locations);
789}
790
791void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100792 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100793}
794
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100795void LocationsBuilderARM::VisitNot(HNot* instruction) {
796 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100797 locations->SetInAt(0, Location::RequiresRegister());
798 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100799 instruction->SetLocations(locations);
800}
801
802void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
803 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100804 __ eor(locations->Out().AsArm().AsCoreRegister(),
805 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100806}
807
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100808void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100809 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
810 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
811 locations->SetInAt(i, Location::Any());
812 }
813 locations->SetOut(Location::Any());
814 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100815}
816
817void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100818 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100819}
820
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100821void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100822 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100823}
824
825void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100826 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
827}
828
829ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
830 return codegen_->GetAssembler();
831}
832
833void ParallelMoveResolverARM::EmitMove(size_t index) {
834 MoveOperands* move = moves_.Get(index);
835 Location source = move->GetSource();
836 Location destination = move->GetDestination();
837
838 if (source.IsRegister()) {
839 if (destination.IsRegister()) {
840 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
841 } else {
842 DCHECK(destination.IsStackSlot());
843 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
844 SP, destination.GetStackIndex());
845 }
846 } else if (source.IsStackSlot()) {
847 if (destination.IsRegister()) {
848 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
849 SP, source.GetStackIndex());
850 } else {
851 DCHECK(destination.IsStackSlot());
852 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
853 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
854 }
855 } else {
856 LOG(FATAL) << "Unimplemented";
857 }
858}
859
860void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
861 __ Mov(IP, reg);
862 __ LoadFromOffset(kLoadWord, reg, SP, mem);
863 __ StoreToOffset(kStoreWord, IP, SP, mem);
864}
865
866void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
867 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
868 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
869 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
870 SP, mem1 + stack_offset);
871 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
872 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
873 SP, mem2 + stack_offset);
874 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
875}
876
877void ParallelMoveResolverARM::EmitSwap(size_t index) {
878 MoveOperands* move = moves_.Get(index);
879 Location source = move->GetSource();
880 Location destination = move->GetDestination();
881
882 if (source.IsRegister() && destination.IsRegister()) {
883 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
884 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
885 __ Mov(IP, source.AsArm().AsCoreRegister());
886 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
887 __ Mov(destination.AsArm().AsCoreRegister(), IP);
888 } else if (source.IsRegister() && destination.IsStackSlot()) {
889 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
890 } else if (source.IsStackSlot() && destination.IsRegister()) {
891 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
892 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
893 Exchange(source.GetStackIndex(), destination.GetStackIndex());
894 } else {
895 LOG(FATAL) << "Unimplemented";
896 }
897}
898
899void ParallelMoveResolverARM::SpillScratch(int reg) {
900 __ Push(static_cast<Register>(reg));
901}
902
903void ParallelMoveResolverARM::RestoreScratch(int reg) {
904 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100905}
906
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000907} // namespace arm
908} // namespace art