blob: 90ec6cfdbdecb174e9123399161be16eb4771978 [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 Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000021#include "mirror/array.h"
22#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070023#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "utils/assembler.h"
25#include "utils/arm/assembler_arm.h"
26#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010027#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000028
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029namespace 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 Geoffrayf12feb82014-07-17 18:32:41 +010037static constexpr bool kExplicitStackOverflowCheck = false;
38
39static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
40static constexpr int kCurrentMethodStackOffset = 0;
41
Nicolas Geoffraye5038322014-07-04 09:41:32 +010042#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
43
44class NullCheckSlowPathARM : public SlowPathCode {
45 public:
46 explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
47
48 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
49 __ Bind(GetEntryLabel());
50 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
51 __ ldr(LR, Address(TR, offset));
52 __ blx(LR);
53 codegen->RecordPcInfo(dex_pc_);
54 }
55
56 private:
57 const uint32_t dex_pc_;
58 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
59};
60
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010061class StackOverflowCheckSlowPathARM : public SlowPathCode {
62 public:
63 StackOverflowCheckSlowPathARM() {}
64
65 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
66 __ Bind(GetEntryLabel());
67 __ LoadFromOffset(kLoadWord, PC, TR,
68 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
69 }
70
71 private:
72 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
73};
74
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075#undef __
76#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -070077
78inline Condition ARMCondition(IfCondition cond) {
79 switch (cond) {
80 case kCondEQ: return EQ;
81 case kCondNE: return NE;
82 case kCondLT: return LT;
83 case kCondLE: return LE;
84 case kCondGT: return GT;
85 case kCondGE: return GE;
86 default:
87 LOG(FATAL) << "Unknown if condition";
88 }
89 return EQ; // Unreachable.
90}
91
92inline Condition ARMOppositeCondition(IfCondition cond) {
93 switch (cond) {
94 case kCondEQ: return NE;
95 case kCondNE: return EQ;
96 case kCondLT: return GE;
97 case kCondLE: return GT;
98 case kCondGT: return LE;
99 case kCondGE: return LT;
100 default:
101 LOG(FATAL) << "Unknown if condition";
102 }
103 return EQ; // Unreachable.
104}
105
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100106void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
107 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
108}
109
110void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
111 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
112}
113
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100114CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
115 : CodeGenerator(graph, kNumberOfRegIds),
116 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100117 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100118 move_resolver_(graph->GetArena(), this),
119 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100120
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100121size_t CodeGeneratorARM::FrameEntrySpillSize() const {
122 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
123}
124
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100125static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
126 return blocked_registers + kNumberOfAllocIds;
127}
128
129ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
130 bool* blocked_registers) const {
131 switch (type) {
132 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100133 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
134 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100135 ArmManagedRegister pair =
136 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
137 blocked_registers[pair.AsRegisterPairLow()] = true;
138 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100139 // Block all other register pairs that share a register with `pair`.
140 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
141 ArmManagedRegister current =
142 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
143 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
144 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
145 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
146 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
147 blocked_register_pairs[i] = true;
148 }
149 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100150 return pair;
151 }
152
153 case Primitive::kPrimByte:
154 case Primitive::kPrimBoolean:
155 case Primitive::kPrimChar:
156 case Primitive::kPrimShort:
157 case Primitive::kPrimInt:
158 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100159 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
160 // Block all register pairs that contain `reg`.
161 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
162 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
163 ArmManagedRegister current =
164 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
165 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
166 blocked_register_pairs[i] = true;
167 }
168 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100169 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
170 }
171
172 case Primitive::kPrimFloat:
173 case Primitive::kPrimDouble:
174 LOG(FATAL) << "Unimplemented register type " << type;
175
176 case Primitive::kPrimVoid:
177 LOG(FATAL) << "Unreachable type " << type;
178 }
179
180 return ManagedRegister::NoRegister();
181}
182
183void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
184 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
185
186 // Don't allocate the dalvik style register pair passing.
187 blocked_register_pairs[R1_R2] = true;
188
189 // Stack register, LR and PC are always reserved.
190 blocked_registers[SP] = true;
191 blocked_registers[LR] = true;
192 blocked_registers[PC] = true;
193
194 // Reserve R4 for suspend check.
195 blocked_registers[R4] = true;
196 blocked_register_pairs[R4_R5] = true;
197
198 // Reserve thread register.
199 blocked_registers[TR] = true;
200
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100201 // Reserve temp register.
202 blocked_registers[IP] = true;
203
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100204 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100205 // We always save and restore R6 and R7 to make sure we can use three
206 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100207 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100208 blocked_registers[R8] = true;
209 blocked_registers[R10] = true;
210 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100211}
212
213size_t CodeGeneratorARM::GetNumberOfRegisters() const {
214 return kNumberOfRegIds;
215}
216
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100217static Location ArmCoreLocation(Register reg) {
218 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
219}
220
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100221InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
222 : HGraphVisitor(graph),
223 assembler_(codegen->GetAssembler()),
224 codegen_(codegen) {}
225
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000226void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100227 bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kArm);
228 if (!skip_overflow_check) {
229 if (kExplicitStackOverflowCheck) {
230 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
231 AddSlowPath(slow_path);
232
233 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
234 __ cmp(SP, ShifterOperand(IP));
235 __ b(slow_path->GetEntryLabel(), CC);
236 } else {
237 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
238 __ ldr(IP, Address(IP, 0));
239 RecordPcInfo(0);
240 }
241 }
242
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100243 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
244 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000245
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100246 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100247 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000248 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000249}
250
251void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100252 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100253 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000254}
255
256void CodeGeneratorARM::Bind(Label* label) {
257 __ Bind(label);
258}
259
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100260Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
261 switch (load->GetType()) {
262 case Primitive::kPrimLong:
263 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
264 break;
265
266 case Primitive::kPrimInt:
267 case Primitive::kPrimNot:
268 return Location::StackSlot(GetStackSlot(load->GetLocal()));
269
270 case Primitive::kPrimFloat:
271 case Primitive::kPrimDouble:
272 LOG(FATAL) << "Unimplemented type " << load->GetType();
273
274 case Primitive::kPrimBoolean:
275 case Primitive::kPrimByte:
276 case Primitive::kPrimChar:
277 case Primitive::kPrimShort:
278 case Primitive::kPrimVoid:
279 LOG(FATAL) << "Unexpected type " << load->GetType();
280 }
281
282 LOG(FATAL) << "Unreachable";
283 return Location();
284}
285
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100286Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
287 switch (type) {
288 case Primitive::kPrimBoolean:
289 case Primitive::kPrimByte:
290 case Primitive::kPrimChar:
291 case Primitive::kPrimShort:
292 case Primitive::kPrimInt:
293 case Primitive::kPrimNot: {
294 uint32_t index = gp_index_++;
295 if (index < calling_convention.GetNumberOfRegisters()) {
296 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
297 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100298 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100299 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100300 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100301
302 case Primitive::kPrimLong: {
303 uint32_t index = gp_index_;
304 gp_index_ += 2;
305 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
306 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
307 calling_convention.GetRegisterPairAt(index)));
308 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
309 return Location::QuickParameter(index);
310 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100311 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100312 }
313 }
314
315 case Primitive::kPrimDouble:
316 case Primitive::kPrimFloat:
317 LOG(FATAL) << "Unimplemented parameter type " << type;
318 break;
319
320 case Primitive::kPrimVoid:
321 LOG(FATAL) << "Unexpected parameter type " << type;
322 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100323 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100324 return Location();
325}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100326
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100327void CodeGeneratorARM::Move32(Location destination, Location source) {
328 if (source.Equals(destination)) {
329 return;
330 }
331 if (destination.IsRegister()) {
332 if (source.IsRegister()) {
333 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
334 } else {
335 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
336 }
337 } else {
338 DCHECK(destination.IsStackSlot());
339 if (source.IsRegister()) {
340 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
341 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100342 __ ldr(IP, Address(SP, source.GetStackIndex()));
343 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100344 }
345 }
346}
347
348void CodeGeneratorARM::Move64(Location destination, Location source) {
349 if (source.Equals(destination)) {
350 return;
351 }
352 if (destination.IsRegister()) {
353 if (source.IsRegister()) {
354 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
355 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
356 } else if (source.IsQuickParameter()) {
357 uint32_t argument_index = source.GetQuickParameterIndex();
358 InvokeDexCallingConvention calling_convention;
359 __ Mov(destination.AsArm().AsRegisterPairLow(),
360 calling_convention.GetRegisterAt(argument_index));
361 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100362 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100363 } else {
364 DCHECK(source.IsDoubleStackSlot());
365 if (destination.AsArm().AsRegisterPair() == R1_R2) {
366 __ ldr(R1, Address(SP, source.GetStackIndex()));
367 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
368 } else {
369 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
370 SP, source.GetStackIndex());
371 }
372 }
373 } else if (destination.IsQuickParameter()) {
374 InvokeDexCallingConvention calling_convention;
375 uint32_t argument_index = destination.GetQuickParameterIndex();
376 if (source.IsRegister()) {
377 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
378 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100379 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100380 } else {
381 DCHECK(source.IsDoubleStackSlot());
382 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100383 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
384 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100385 }
386 } else {
387 DCHECK(destination.IsDoubleStackSlot());
388 if (source.IsRegister()) {
389 if (source.AsArm().AsRegisterPair() == R1_R2) {
390 __ str(R1, Address(SP, destination.GetStackIndex()));
391 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
392 } else {
393 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
394 SP, destination.GetStackIndex());
395 }
396 } else if (source.IsQuickParameter()) {
397 InvokeDexCallingConvention calling_convention;
398 uint32_t argument_index = source.GetQuickParameterIndex();
399 __ str(calling_convention.GetRegisterAt(argument_index),
400 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100401 __ ldr(R0,
402 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
403 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100404 } else {
405 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100406 __ ldr(IP, Address(SP, source.GetStackIndex()));
407 __ str(IP, Address(SP, destination.GetStackIndex()));
408 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
409 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100410 }
411 }
412}
413
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100414void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100415 LocationSummary* locations = instruction->GetLocations();
416 if (locations != nullptr && locations->Out().Equals(location)) {
417 return;
418 }
419
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100420 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100421 int32_t value = instruction->AsIntConstant()->GetValue();
422 if (location.IsRegister()) {
423 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
424 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100425 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100426 __ LoadImmediate(IP, value);
427 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100428 }
429 } else if (instruction->AsLongConstant() != nullptr) {
430 int64_t value = instruction->AsLongConstant()->GetValue();
431 if (location.IsRegister()) {
432 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
433 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
434 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100435 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100436 __ LoadImmediate(IP, Low32Bits(value));
437 __ str(IP, Address(SP, location.GetStackIndex()));
438 __ LoadImmediate(IP, High32Bits(value));
439 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100440 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100441 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100442 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
443 switch (instruction->GetType()) {
444 case Primitive::kPrimBoolean:
445 case Primitive::kPrimByte:
446 case Primitive::kPrimChar:
447 case Primitive::kPrimShort:
448 case Primitive::kPrimInt:
449 case Primitive::kPrimNot:
450 Move32(location, Location::StackSlot(stack_slot));
451 break;
452
453 case Primitive::kPrimLong:
454 Move64(location, Location::DoubleStackSlot(stack_slot));
455 break;
456
457 default:
458 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
459 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000460 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100461 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100462 switch (instruction->GetType()) {
463 case Primitive::kPrimBoolean:
464 case Primitive::kPrimByte:
465 case Primitive::kPrimChar:
466 case Primitive::kPrimShort:
467 case Primitive::kPrimNot:
468 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100469 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100470 break;
471
472 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100473 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100474 break;
475
476 default:
477 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
478 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000479 }
480}
481
482void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000483 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000484}
485
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000486void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000487 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000488 if (GetGraph()->GetExitBlock() == successor) {
489 codegen_->GenerateFrameExit();
490 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
491 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000492 }
493}
494
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000495void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000496 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000497}
498
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000499void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000500 if (kIsDebugBuild) {
501 __ Comment("Unreachable");
502 __ bkpt(0);
503 }
504}
505
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000506void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000507 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100508 HInstruction* cond = if_instr->InputAt(0);
509 DCHECK(cond->IsCondition());
510 HCondition* condition = cond->AsCondition();
511 if (condition->NeedsMaterialization()) {
512 locations->SetInAt(0, Location::Any());
513 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000514 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000515}
516
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000517void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700518 HInstruction* cond = if_instr->InputAt(0);
519 DCHECK(cond->IsCondition());
520 HCondition* condition = cond->AsCondition();
521 if (condition->NeedsMaterialization()) {
522 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100523 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700524 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
525 ShifterOperand(0));
526 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
527 } else {
528 // Condition has not been materialized, use its inputs as the comparison and its
529 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100530 LocationSummary* locations = condition->GetLocations();
531 if (locations->InAt(1).IsRegister()) {
532 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
533 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
534 } else {
535 DCHECK(locations->InAt(1).IsConstant());
536 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
537 ShifterOperand operand;
538 if (ShifterOperand::CanHoldArm(value, &operand)) {
539 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
540 } else {
541 Register temp = IP;
542 __ LoadImmediate(temp, value);
543 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
544 }
545 }
Dave Allison20dfc792014-06-16 20:44:29 -0700546 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
547 ARMCondition(condition->GetCondition()));
548 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100549
Dave Allison20dfc792014-06-16 20:44:29 -0700550 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
551 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000552 }
553}
554
Dave Allison20dfc792014-06-16 20:44:29 -0700555
556void LocationsBuilderARM::VisitCondition(HCondition* comp) {
557 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100558 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100559 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100560 if (comp->NeedsMaterialization()) {
561 locations->SetOut(Location::RequiresRegister());
562 }
Dave Allison20dfc792014-06-16 20:44:29 -0700563 comp->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000564}
565
Dave Allison20dfc792014-06-16 20:44:29 -0700566void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100567 if (!comp->NeedsMaterialization()) return;
568
569 LocationSummary* locations = comp->GetLocations();
570 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700571 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
572 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100573 } else {
574 DCHECK(locations->InAt(1).IsConstant());
575 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
576 ShifterOperand operand;
577 if (ShifterOperand::CanHoldArm(value, &operand)) {
578 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
579 } else {
580 Register temp = IP;
581 __ LoadImmediate(temp, value);
582 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
583 }
Dave Allison20dfc792014-06-16 20:44:29 -0700584 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100585 __ it(ARMCondition(comp->GetCondition()), kItElse);
586 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
587 ARMCondition(comp->GetCondition()));
588 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
589 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700590}
591
592void LocationsBuilderARM::VisitEqual(HEqual* comp) {
593 VisitCondition(comp);
594}
595
596void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
597 VisitCondition(comp);
598}
599
600void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
601 VisitCondition(comp);
602}
603
604void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
605 VisitCondition(comp);
606}
607
608void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
609 VisitCondition(comp);
610}
611
612void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
613 VisitCondition(comp);
614}
615
616void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
617 VisitCondition(comp);
618}
619
620void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
621 VisitCondition(comp);
622}
623
624void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
625 VisitCondition(comp);
626}
627
628void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
629 VisitCondition(comp);
630}
631
632void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
633 VisitCondition(comp);
634}
635
636void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
637 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000638}
639
640void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000641 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000642}
643
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000644void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
645 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000646}
647
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000648void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100649 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000650}
651
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000652void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100653 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000654}
655
656void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000657 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100658 switch (store->InputAt(1)->GetType()) {
659 case Primitive::kPrimBoolean:
660 case Primitive::kPrimByte:
661 case Primitive::kPrimChar:
662 case Primitive::kPrimShort:
663 case Primitive::kPrimInt:
664 case Primitive::kPrimNot:
665 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
666 break;
667
668 case Primitive::kPrimLong:
669 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
670 break;
671
672 default:
673 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
674 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000675 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000676}
677
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000678void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000679}
680
681void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100682 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100683 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100684 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000685}
686
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000687void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000688}
689
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100690void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100691 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100692 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100693 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100694}
695
696void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
697 // Will be generated at use site.
698}
699
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000700void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000701 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000702}
703
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000704void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
705 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000706}
707
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000708void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000709 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100710 switch (ret->InputAt(0)->GetType()) {
711 case Primitive::kPrimBoolean:
712 case Primitive::kPrimByte:
713 case Primitive::kPrimChar:
714 case Primitive::kPrimShort:
715 case Primitive::kPrimInt:
716 case Primitive::kPrimNot:
717 locations->SetInAt(0, ArmCoreLocation(R0));
718 break;
719
720 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100721 locations->SetInAt(
722 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100723 break;
724
725 default:
726 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
727 }
728
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000729 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000730}
731
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000732void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100733 if (kIsDebugBuild) {
734 switch (ret->InputAt(0)->GetType()) {
735 case Primitive::kPrimBoolean:
736 case Primitive::kPrimByte:
737 case Primitive::kPrimChar:
738 case Primitive::kPrimShort:
739 case Primitive::kPrimInt:
740 case Primitive::kPrimNot:
741 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
742 break;
743
744 case Primitive::kPrimLong:
745 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
746 break;
747
748 default:
749 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
750 }
751 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000752 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000753}
754
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000755void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100756 codegen_->MarkNotLeaf();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000757 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100758 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100759
760 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100761 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100762 HInstruction* input = invoke->InputAt(i);
763 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
764 }
765
766 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100767 case Primitive::kPrimBoolean:
768 case Primitive::kPrimByte:
769 case Primitive::kPrimChar:
770 case Primitive::kPrimShort:
771 case Primitive::kPrimInt:
772 case Primitive::kPrimNot:
773 locations->SetOut(ArmCoreLocation(R0));
774 break;
775
776 case Primitive::kPrimLong:
777 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
778 break;
779
780 case Primitive::kPrimVoid:
781 break;
782
783 case Primitive::kPrimDouble:
784 case Primitive::kPrimFloat:
785 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
786 break;
787 }
788
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000789 invoke->SetLocations(locations);
790}
791
792void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100793 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000794}
795
796void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100797 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100798 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
799 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100800 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000801
802 // TODO: Implement all kinds of calls:
803 // 1) boot -> boot
804 // 2) app -> boot
805 // 3) app -> app
806 //
807 // Currently we implement the app -> app logic, which looks up in the resolve cache.
808
809 // temp = method;
810 LoadCurrentMethod(temp);
811 // temp = temp->dex_cache_resolved_methods_;
812 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
813 // temp = temp[index_in_cache]
814 __ ldr(temp, Address(temp, index_in_cache));
815 // LR = temp[offset_of_quick_compiled_code]
816 __ ldr(LR, Address(temp,
817 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
818 // LR()
819 __ blx(LR);
820
821 codegen_->RecordPcInfo(invoke->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100822 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000823}
824
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000825void LocationsBuilderARM::VisitAdd(HAdd* add) {
826 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
827 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100828 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100829 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100830 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100831 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100832 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 break;
834 }
835
836 case Primitive::kPrimBoolean:
837 case Primitive::kPrimByte:
838 case Primitive::kPrimChar:
839 case Primitive::kPrimShort:
840 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
841 break;
842
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000843 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100844 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000845 }
846 add->SetLocations(locations);
847}
848
849void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
850 LocationSummary* locations = add->GetLocations();
851 switch (add->GetResultType()) {
852 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100853 if (locations->InAt(1).IsRegister()) {
854 __ add(locations->Out().AsArm().AsCoreRegister(),
855 locations->InAt(0).AsArm().AsCoreRegister(),
856 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
857 } else {
858 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
859 locations->InAt(0).AsArm().AsCoreRegister(),
860 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
861 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000862 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863
864 case Primitive::kPrimLong:
865 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
866 locations->InAt(0).AsArm().AsRegisterPairLow(),
867 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
868 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
869 locations->InAt(0).AsArm().AsRegisterPairHigh(),
870 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
871 break;
872
873 case Primitive::kPrimBoolean:
874 case Primitive::kPrimByte:
875 case Primitive::kPrimChar:
876 case Primitive::kPrimShort:
877 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
878 break;
879
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000880 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100881 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000882 }
883}
884
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100885void LocationsBuilderARM::VisitSub(HSub* sub) {
886 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
887 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100888 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100889 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100890 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100891 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100892 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100893 break;
894 }
895
896 case Primitive::kPrimBoolean:
897 case Primitive::kPrimByte:
898 case Primitive::kPrimChar:
899 case Primitive::kPrimShort:
900 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
901 break;
902
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100903 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100904 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100905 }
906 sub->SetLocations(locations);
907}
908
909void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
910 LocationSummary* locations = sub->GetLocations();
911 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100912 case Primitive::kPrimInt: {
913 if (locations->InAt(1).IsRegister()) {
914 __ sub(locations->Out().AsArm().AsCoreRegister(),
915 locations->InAt(0).AsArm().AsCoreRegister(),
916 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
917 } else {
918 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
919 locations->InAt(0).AsArm().AsCoreRegister(),
920 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
921 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100922 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100923 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100924
925 case Primitive::kPrimLong:
926 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
927 locations->InAt(0).AsArm().AsRegisterPairLow(),
928 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
929 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
930 locations->InAt(0).AsArm().AsRegisterPairHigh(),
931 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
932 break;
933
934 case Primitive::kPrimBoolean:
935 case Primitive::kPrimByte:
936 case Primitive::kPrimChar:
937 case Primitive::kPrimShort:
938 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
939 break;
940
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100941 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100942 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100943 }
944}
945
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100946static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
947static constexpr size_t kRuntimeParameterCoreRegistersLength =
948 arraysize(kRuntimeParameterCoreRegisters);
949
950class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
951 public:
952 InvokeRuntimeCallingConvention()
953 : CallingConvention(kRuntimeParameterCoreRegisters,
954 kRuntimeParameterCoreRegistersLength) {}
955
956 private:
957 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
958};
959
960void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100961 codegen_->MarkNotLeaf();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100962 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100963 InvokeRuntimeCallingConvention calling_convention;
964 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
965 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100966 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100967 instruction->SetLocations(locations);
968}
969
970void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
971 InvokeRuntimeCallingConvention calling_convention;
972 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
973 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
974
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100975 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100976 __ ldr(LR, Address(TR, offset));
977 __ blx(LR);
978
979 codegen_->RecordPcInfo(instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100980 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100981}
982
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100983void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
984 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100985 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
986 if (location.IsStackSlot()) {
987 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
988 } else if (location.IsDoubleStackSlot()) {
989 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100990 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100991 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100992 instruction->SetLocations(locations);
993}
994
995void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100996 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100997}
998
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100999void LocationsBuilderARM::VisitNot(HNot* instruction) {
1000 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001001 locations->SetInAt(0, Location::RequiresRegister());
1002 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001003 instruction->SetLocations(locations);
1004}
1005
1006void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1007 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001008 __ eor(locations->Out().AsArm().AsCoreRegister(),
1009 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001010}
1011
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001012void LocationsBuilderARM::VisitCompare(HCompare* compare) {
1013 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
1014 locations->SetInAt(0, Location::RequiresRegister());
1015 locations->SetInAt(1, Location::RequiresRegister());
1016 locations->SetOut(Location::RequiresRegister());
1017 compare->SetLocations(locations);
1018}
1019
1020void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1021 Label greater, done;
1022 LocationSummary* locations = compare->GetLocations();
1023 switch (compare->InputAt(0)->GetType()) {
1024 case Primitive::kPrimLong: {
1025 Register output = locations->Out().AsArm().AsCoreRegister();
1026 ArmManagedRegister left = locations->InAt(0).AsArm();
1027 ArmManagedRegister right = locations->InAt(1).AsArm();
1028 Label less, greater, done;
1029 __ cmp(left.AsRegisterPairHigh(),
1030 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1031 __ b(&less, LT);
1032 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001033 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1034 // the status flags.
1035 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001036 __ cmp(left.AsRegisterPairLow(),
1037 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001038 __ b(&done, EQ);
1039 __ b(&less, CC);
1040
1041 __ Bind(&greater);
1042 __ LoadImmediate(output, 1);
1043 __ b(&done);
1044
1045 __ Bind(&less);
1046 __ LoadImmediate(output, -1);
1047
1048 __ Bind(&done);
1049 break;
1050 }
1051 default:
1052 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1053 }
1054}
1055
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001056void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001057 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1058 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1059 locations->SetInAt(i, Location::Any());
1060 }
1061 locations->SetOut(Location::Any());
1062 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001063}
1064
1065void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001066 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001067}
1068
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001069void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1070 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1071 locations->SetInAt(0, Location::RequiresRegister());
1072 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001073 // Temporary registers for the write barrier.
1074 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
1075 locations->AddTemp(Location::RequiresRegister());
1076 locations->AddTemp(Location::RequiresRegister());
1077 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001078 instruction->SetLocations(locations);
1079}
1080
1081void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1082 LocationSummary* locations = instruction->GetLocations();
1083 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1084 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1085 Primitive::Type field_type = instruction->InputAt(1)->GetType();
1086
1087 switch (field_type) {
1088 case Primitive::kPrimBoolean:
1089 case Primitive::kPrimByte: {
1090 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1091 __ StoreToOffset(kStoreByte, value, obj, offset);
1092 break;
1093 }
1094
1095 case Primitive::kPrimShort:
1096 case Primitive::kPrimChar: {
1097 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1098 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1099 break;
1100 }
1101
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001102 case Primitive::kPrimInt: {
1103 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1104 __ StoreToOffset(kStoreWord, value, obj, offset);
1105 break;
1106 }
1107
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001108 case Primitive::kPrimNot: {
1109 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1110 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001111
1112 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1113 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1114 Label is_null;
1115 __ CompareAndBranchIfZero(value, &is_null);
1116 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1117 __ Lsr(temp, obj, gc::accounting::CardTable::kCardShift);
1118 __ strb(card, Address(card, temp));
1119 __ Bind(&is_null);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001120 break;
1121 }
1122
1123 case Primitive::kPrimLong: {
1124 ArmManagedRegister value = locations->InAt(1).AsArm();
1125 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1126 break;
1127 }
1128
1129 case Primitive::kPrimFloat:
1130 case Primitive::kPrimDouble:
1131 LOG(FATAL) << "Unimplemented register type " << field_type;
1132
1133 case Primitive::kPrimVoid:
1134 LOG(FATAL) << "Unreachable type " << field_type;
1135 }
1136}
1137
1138void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1139 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1140 locations->SetInAt(0, Location::RequiresRegister());
1141 locations->SetOut(Location::RequiresRegister());
1142 instruction->SetLocations(locations);
1143}
1144
1145void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1146 LocationSummary* locations = instruction->GetLocations();
1147 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1148 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1149
1150 switch (instruction->GetType()) {
1151 case Primitive::kPrimBoolean: {
1152 Register out = locations->Out().AsArm().AsCoreRegister();
1153 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1154 break;
1155 }
1156
1157 case Primitive::kPrimByte: {
1158 Register out = locations->Out().AsArm().AsCoreRegister();
1159 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1160 break;
1161 }
1162
1163 case Primitive::kPrimShort: {
1164 Register out = locations->Out().AsArm().AsCoreRegister();
1165 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1166 break;
1167 }
1168
1169 case Primitive::kPrimChar: {
1170 Register out = locations->Out().AsArm().AsCoreRegister();
1171 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1172 break;
1173 }
1174
1175 case Primitive::kPrimInt:
1176 case Primitive::kPrimNot: {
1177 Register out = locations->Out().AsArm().AsCoreRegister();
1178 __ LoadFromOffset(kLoadWord, out, obj, offset);
1179 break;
1180 }
1181
1182 case Primitive::kPrimLong: {
1183 // TODO: support volatile.
1184 ArmManagedRegister out = locations->Out().AsArm();
1185 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1186 break;
1187 }
1188
1189 case Primitive::kPrimFloat:
1190 case Primitive::kPrimDouble:
1191 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1192
1193 case Primitive::kPrimVoid:
1194 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1195 }
1196}
1197
1198void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1199 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1200 locations->SetInAt(0, Location::RequiresRegister());
1201 // TODO: Have a normalization phase that makes this instruction never used.
1202 locations->SetOut(Location::SameAsFirstInput());
1203 instruction->SetLocations(locations);
1204}
1205
1206void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1207 SlowPathCode* slow_path =
1208 new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1209 codegen_->AddSlowPath(slow_path);
1210
1211 LocationSummary* locations = instruction->GetLocations();
1212 Location obj = locations->InAt(0);
1213 DCHECK(obj.Equals(locations->Out()));
1214
1215 if (obj.IsRegister()) {
1216 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1217 }
1218 __ b(slow_path->GetEntryLabel(), EQ);
1219}
1220
1221void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1222 temp->SetLocations(nullptr);
1223}
1224
1225void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1226 // Nothing to do, this is driven by the code generator.
1227}
1228
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001229void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001230 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001231}
1232
1233void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001234 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1235}
1236
1237ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1238 return codegen_->GetAssembler();
1239}
1240
1241void ParallelMoveResolverARM::EmitMove(size_t index) {
1242 MoveOperands* move = moves_.Get(index);
1243 Location source = move->GetSource();
1244 Location destination = move->GetDestination();
1245
1246 if (source.IsRegister()) {
1247 if (destination.IsRegister()) {
1248 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1249 } else {
1250 DCHECK(destination.IsStackSlot());
1251 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1252 SP, destination.GetStackIndex());
1253 }
1254 } else if (source.IsStackSlot()) {
1255 if (destination.IsRegister()) {
1256 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1257 SP, source.GetStackIndex());
1258 } else {
1259 DCHECK(destination.IsStackSlot());
1260 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1261 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1262 }
1263 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001264 DCHECK(source.IsConstant());
1265 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1266 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1267 if (destination.IsRegister()) {
1268 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1269 } else {
1270 DCHECK(destination.IsStackSlot());
1271 __ LoadImmediate(IP, value);
1272 __ str(IP, Address(SP, destination.GetStackIndex()));
1273 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001274 }
1275}
1276
1277void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1278 __ Mov(IP, reg);
1279 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1280 __ StoreToOffset(kStoreWord, IP, SP, mem);
1281}
1282
1283void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1284 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1285 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1286 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1287 SP, mem1 + stack_offset);
1288 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1289 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1290 SP, mem2 + stack_offset);
1291 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1292}
1293
1294void ParallelMoveResolverARM::EmitSwap(size_t index) {
1295 MoveOperands* move = moves_.Get(index);
1296 Location source = move->GetSource();
1297 Location destination = move->GetDestination();
1298
1299 if (source.IsRegister() && destination.IsRegister()) {
1300 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1301 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1302 __ Mov(IP, source.AsArm().AsCoreRegister());
1303 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1304 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1305 } else if (source.IsRegister() && destination.IsStackSlot()) {
1306 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1307 } else if (source.IsStackSlot() && destination.IsRegister()) {
1308 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1309 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1310 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1311 } else {
1312 LOG(FATAL) << "Unimplemented";
1313 }
1314}
1315
1316void ParallelMoveResolverARM::SpillScratch(int reg) {
1317 __ Push(static_cast<Register>(reg));
1318}
1319
1320void ParallelMoveResolverARM::RestoreScratch(int reg) {
1321 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001322}
1323
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001324} // namespace arm
1325} // namespace art