blob: d8e9dec5282b76c2cc2fe0d694381ebe2dc27462 [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"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070024#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010025#include "utils/assembler.h"
26#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010028#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000029
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031
32arm::ArmManagedRegister Location::AsArm() const {
33 return reg().AsArm();
34}
35
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace arm {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038static constexpr bool kExplicitStackOverflowCheck = false;
39
40static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
41static constexpr int kCurrentMethodStackOffset = 0;
42
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010043static Location ArmCoreLocation(Register reg) {
44 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
45}
46
47static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
48static constexpr size_t kRuntimeParameterCoreRegistersLength =
49 arraysize(kRuntimeParameterCoreRegisters);
50
51class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
52 public:
53 InvokeRuntimeCallingConvention()
54 : CallingConvention(kRuntimeParameterCoreRegisters,
55 kRuntimeParameterCoreRegistersLength) {}
56
57 private:
58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
59};
60
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
62
63class NullCheckSlowPathARM : public SlowPathCode {
64 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010065 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066
67 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
68 __ Bind(GetEntryLabel());
69 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
70 __ ldr(LR, Address(TR, offset));
71 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +010072 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 }
74
75 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
78};
79
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010080class StackOverflowCheckSlowPathARM : public SlowPathCode {
81 public:
82 StackOverflowCheckSlowPathARM() {}
83
84 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
85 __ Bind(GetEntryLabel());
86 __ LoadFromOffset(kLoadWord, PC, TR,
87 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
88 }
89
90 private:
91 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
92};
93
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000094class SuspendCheckSlowPathARM : public SlowPathCode {
95 public:
96 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction)
97 : instruction_(instruction) {}
98
99 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
100 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100101 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000102 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
103 __ ldr(LR, Address(TR, offset));
104 __ blx(LR);
105 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100106 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000107 __ b(GetReturnLabel());
108 }
109
110 Label* GetReturnLabel() { return &return_label_; }
111
112 private:
113 HSuspendCheck* const instruction_;
114 Label return_label_;
115
116 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
117};
118
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100119class BoundsCheckSlowPathARM : public SlowPathCode {
120 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100121 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
122 Location index_location,
123 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100124 : instruction_(instruction),
125 index_location_(index_location),
126 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127
128 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
129 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
130 __ Bind(GetEntryLabel());
131 InvokeRuntimeCallingConvention calling_convention;
132 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
133 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
134 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
135 __ ldr(LR, Address(TR, offset));
136 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100137 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138 }
139
140 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100141 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100142 const Location index_location_;
143 const Location length_location_;
144
145 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
146};
147
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100148#undef __
149#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700150
151inline Condition ARMCondition(IfCondition cond) {
152 switch (cond) {
153 case kCondEQ: return EQ;
154 case kCondNE: return NE;
155 case kCondLT: return LT;
156 case kCondLE: return LE;
157 case kCondGT: return GT;
158 case kCondGE: return GE;
159 default:
160 LOG(FATAL) << "Unknown if condition";
161 }
162 return EQ; // Unreachable.
163}
164
165inline Condition ARMOppositeCondition(IfCondition cond) {
166 switch (cond) {
167 case kCondEQ: return NE;
168 case kCondNE: return EQ;
169 case kCondLT: return GE;
170 case kCondLE: return GT;
171 case kCondGT: return LE;
172 case kCondGE: return LT;
173 default:
174 LOG(FATAL) << "Unknown if condition";
175 }
176 return EQ; // Unreachable.
177}
178
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100179void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
180 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
181}
182
183void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
184 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
185}
186
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100187void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
188 __ str(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
189}
190
191void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
192 __ ldr(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
193}
194
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100195CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
196 : CodeGenerator(graph, kNumberOfRegIds),
197 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100198 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100199 move_resolver_(graph->GetArena(), this),
200 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100201
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100202size_t CodeGeneratorARM::FrameEntrySpillSize() const {
203 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
204}
205
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100206static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
207 return blocked_registers + kNumberOfAllocIds;
208}
209
210ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
211 bool* blocked_registers) const {
212 switch (type) {
213 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100214 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
215 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100216 ArmManagedRegister pair =
217 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
218 blocked_registers[pair.AsRegisterPairLow()] = true;
219 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100220 // Block all other register pairs that share a register with `pair`.
221 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
222 ArmManagedRegister current =
223 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
224 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
225 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
226 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
227 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
228 blocked_register_pairs[i] = true;
229 }
230 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100231 return pair;
232 }
233
234 case Primitive::kPrimByte:
235 case Primitive::kPrimBoolean:
236 case Primitive::kPrimChar:
237 case Primitive::kPrimShort:
238 case Primitive::kPrimInt:
239 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100240 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
241 // Block all register pairs that contain `reg`.
242 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
243 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
244 ArmManagedRegister current =
245 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
246 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
247 blocked_register_pairs[i] = true;
248 }
249 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100250 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
251 }
252
253 case Primitive::kPrimFloat:
254 case Primitive::kPrimDouble:
255 LOG(FATAL) << "Unimplemented register type " << type;
256
257 case Primitive::kPrimVoid:
258 LOG(FATAL) << "Unreachable type " << type;
259 }
260
261 return ManagedRegister::NoRegister();
262}
263
264void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
265 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
266
267 // Don't allocate the dalvik style register pair passing.
268 blocked_register_pairs[R1_R2] = true;
269
270 // Stack register, LR and PC are always reserved.
271 blocked_registers[SP] = true;
272 blocked_registers[LR] = true;
273 blocked_registers[PC] = true;
274
275 // Reserve R4 for suspend check.
276 blocked_registers[R4] = true;
277 blocked_register_pairs[R4_R5] = true;
278
279 // Reserve thread register.
280 blocked_registers[TR] = true;
281
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100282 // Reserve temp register.
283 blocked_registers[IP] = true;
284
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100285 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100286 // We always save and restore R6 and R7 to make sure we can use three
287 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100288 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100289 blocked_registers[R8] = true;
290 blocked_registers[R10] = true;
291 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100292}
293
294size_t CodeGeneratorARM::GetNumberOfRegisters() const {
295 return kNumberOfRegIds;
296}
297
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100298InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
299 : HGraphVisitor(graph),
300 assembler_(codegen->GetAssembler()),
301 codegen_(codegen) {}
302
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000303void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700304 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100305 if (!skip_overflow_check) {
306 if (kExplicitStackOverflowCheck) {
307 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
308 AddSlowPath(slow_path);
309
310 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
311 __ cmp(SP, ShifterOperand(IP));
312 __ b(slow_path->GetEntryLabel(), CC);
313 } else {
314 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
315 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100316 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100317 }
318 }
319
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100320 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
321 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000322
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100323 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100324 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000325 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000326}
327
328void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100329 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100330 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000331}
332
333void CodeGeneratorARM::Bind(Label* label) {
334 __ Bind(label);
335}
336
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100337Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
338 switch (load->GetType()) {
339 case Primitive::kPrimLong:
340 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
341 break;
342
343 case Primitive::kPrimInt:
344 case Primitive::kPrimNot:
345 return Location::StackSlot(GetStackSlot(load->GetLocal()));
346
347 case Primitive::kPrimFloat:
348 case Primitive::kPrimDouble:
349 LOG(FATAL) << "Unimplemented type " << load->GetType();
350
351 case Primitive::kPrimBoolean:
352 case Primitive::kPrimByte:
353 case Primitive::kPrimChar:
354 case Primitive::kPrimShort:
355 case Primitive::kPrimVoid:
356 LOG(FATAL) << "Unexpected type " << load->GetType();
357 }
358
359 LOG(FATAL) << "Unreachable";
360 return Location();
361}
362
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100363Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
364 switch (type) {
365 case Primitive::kPrimBoolean:
366 case Primitive::kPrimByte:
367 case Primitive::kPrimChar:
368 case Primitive::kPrimShort:
369 case Primitive::kPrimInt:
370 case Primitive::kPrimNot: {
371 uint32_t index = gp_index_++;
372 if (index < calling_convention.GetNumberOfRegisters()) {
373 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
374 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100375 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100376 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100377 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100378
379 case Primitive::kPrimLong: {
380 uint32_t index = gp_index_;
381 gp_index_ += 2;
382 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
383 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
384 calling_convention.GetRegisterPairAt(index)));
385 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
386 return Location::QuickParameter(index);
387 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100388 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100389 }
390 }
391
392 case Primitive::kPrimDouble:
393 case Primitive::kPrimFloat:
394 LOG(FATAL) << "Unimplemented parameter type " << type;
395 break;
396
397 case Primitive::kPrimVoid:
398 LOG(FATAL) << "Unexpected parameter type " << type;
399 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100400 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100401 return Location();
402}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100403
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100404void CodeGeneratorARM::Move32(Location destination, Location source) {
405 if (source.Equals(destination)) {
406 return;
407 }
408 if (destination.IsRegister()) {
409 if (source.IsRegister()) {
410 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
411 } else {
412 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
413 }
414 } else {
415 DCHECK(destination.IsStackSlot());
416 if (source.IsRegister()) {
417 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
418 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100419 __ ldr(IP, Address(SP, source.GetStackIndex()));
420 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100421 }
422 }
423}
424
425void CodeGeneratorARM::Move64(Location destination, Location source) {
426 if (source.Equals(destination)) {
427 return;
428 }
429 if (destination.IsRegister()) {
430 if (source.IsRegister()) {
431 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
432 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
433 } else if (source.IsQuickParameter()) {
434 uint32_t argument_index = source.GetQuickParameterIndex();
435 InvokeDexCallingConvention calling_convention;
436 __ Mov(destination.AsArm().AsRegisterPairLow(),
437 calling_convention.GetRegisterAt(argument_index));
438 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100439 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100440 } else {
441 DCHECK(source.IsDoubleStackSlot());
442 if (destination.AsArm().AsRegisterPair() == R1_R2) {
443 __ ldr(R1, Address(SP, source.GetStackIndex()));
444 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
445 } else {
446 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
447 SP, source.GetStackIndex());
448 }
449 }
450 } else if (destination.IsQuickParameter()) {
451 InvokeDexCallingConvention calling_convention;
452 uint32_t argument_index = destination.GetQuickParameterIndex();
453 if (source.IsRegister()) {
454 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
455 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100456 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100457 } else {
458 DCHECK(source.IsDoubleStackSlot());
459 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100460 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
461 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100462 }
463 } else {
464 DCHECK(destination.IsDoubleStackSlot());
465 if (source.IsRegister()) {
466 if (source.AsArm().AsRegisterPair() == R1_R2) {
467 __ str(R1, Address(SP, destination.GetStackIndex()));
468 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
469 } else {
470 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
471 SP, destination.GetStackIndex());
472 }
473 } else if (source.IsQuickParameter()) {
474 InvokeDexCallingConvention calling_convention;
475 uint32_t argument_index = source.GetQuickParameterIndex();
476 __ str(calling_convention.GetRegisterAt(argument_index),
477 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100478 __ ldr(R0,
479 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
480 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100481 } else {
482 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100483 __ ldr(IP, Address(SP, source.GetStackIndex()));
484 __ str(IP, Address(SP, destination.GetStackIndex()));
485 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
486 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100487 }
488 }
489}
490
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100491void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100492 LocationSummary* locations = instruction->GetLocations();
493 if (locations != nullptr && locations->Out().Equals(location)) {
494 return;
495 }
496
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100497 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100498 int32_t value = instruction->AsIntConstant()->GetValue();
499 if (location.IsRegister()) {
500 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
501 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100502 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100503 __ LoadImmediate(IP, value);
504 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100505 }
506 } else if (instruction->AsLongConstant() != nullptr) {
507 int64_t value = instruction->AsLongConstant()->GetValue();
508 if (location.IsRegister()) {
509 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
510 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
511 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100512 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100513 __ LoadImmediate(IP, Low32Bits(value));
514 __ str(IP, Address(SP, location.GetStackIndex()));
515 __ LoadImmediate(IP, High32Bits(value));
516 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100517 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100518 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100519 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
520 switch (instruction->GetType()) {
521 case Primitive::kPrimBoolean:
522 case Primitive::kPrimByte:
523 case Primitive::kPrimChar:
524 case Primitive::kPrimShort:
525 case Primitive::kPrimInt:
526 case Primitive::kPrimNot:
527 Move32(location, Location::StackSlot(stack_slot));
528 break;
529
530 case Primitive::kPrimLong:
531 Move64(location, Location::DoubleStackSlot(stack_slot));
532 break;
533
534 default:
535 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
536 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000537 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100538 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100539 switch (instruction->GetType()) {
540 case Primitive::kPrimBoolean:
541 case Primitive::kPrimByte:
542 case Primitive::kPrimChar:
543 case Primitive::kPrimShort:
544 case Primitive::kPrimNot:
545 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100546 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100547 break;
548
549 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100550 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100551 break;
552
553 default:
554 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
555 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000556 }
557}
558
559void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000560 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000561}
562
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000563void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000564 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000565 if (GetGraph()->GetExitBlock() == successor) {
566 codegen_->GenerateFrameExit();
567 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
568 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000569 }
570}
571
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000572void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000573 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000574}
575
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000576void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000577 if (kIsDebugBuild) {
578 __ Comment("Unreachable");
579 __ bkpt(0);
580 }
581}
582
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000583void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100584 LocationSummary* locations =
585 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100586 HInstruction* cond = if_instr->InputAt(0);
587 DCHECK(cond->IsCondition());
588 HCondition* condition = cond->AsCondition();
589 if (condition->NeedsMaterialization()) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100590 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100591 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000592}
593
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000594void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700595 HInstruction* cond = if_instr->InputAt(0);
596 DCHECK(cond->IsCondition());
597 HCondition* condition = cond->AsCondition();
598 if (condition->NeedsMaterialization()) {
599 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100600 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700601 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
602 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100603 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700604 } else {
605 // Condition has not been materialized, use its inputs as the comparison and its
606 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100607 LocationSummary* locations = condition->GetLocations();
608 if (locations->InAt(1).IsRegister()) {
609 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
610 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
611 } else {
612 DCHECK(locations->InAt(1).IsConstant());
613 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
614 ShifterOperand operand;
615 if (ShifterOperand::CanHoldArm(value, &operand)) {
616 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
617 } else {
618 Register temp = IP;
619 __ LoadImmediate(temp, value);
620 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
621 }
622 }
Dave Allison20dfc792014-06-16 20:44:29 -0700623 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
624 ARMCondition(condition->GetCondition()));
625 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100626
Dave Allison20dfc792014-06-16 20:44:29 -0700627 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
628 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000629 }
630}
631
Dave Allison20dfc792014-06-16 20:44:29 -0700632
633void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100634 LocationSummary* locations =
635 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100636 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100637 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100638 if (comp->NeedsMaterialization()) {
639 locations->SetOut(Location::RequiresRegister());
640 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000641}
642
Dave Allison20dfc792014-06-16 20:44:29 -0700643void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100644 if (!comp->NeedsMaterialization()) return;
645
646 LocationSummary* locations = comp->GetLocations();
647 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700648 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
649 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100650 } else {
651 DCHECK(locations->InAt(1).IsConstant());
652 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
653 ShifterOperand operand;
654 if (ShifterOperand::CanHoldArm(value, &operand)) {
655 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
656 } else {
657 Register temp = IP;
658 __ LoadImmediate(temp, value);
659 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
660 }
Dave Allison20dfc792014-06-16 20:44:29 -0700661 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100662 __ it(ARMCondition(comp->GetCondition()), kItElse);
663 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
664 ARMCondition(comp->GetCondition()));
665 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
666 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700667}
668
669void LocationsBuilderARM::VisitEqual(HEqual* comp) {
670 VisitCondition(comp);
671}
672
673void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
674 VisitCondition(comp);
675}
676
677void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
678 VisitCondition(comp);
679}
680
681void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
682 VisitCondition(comp);
683}
684
685void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
686 VisitCondition(comp);
687}
688
689void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
690 VisitCondition(comp);
691}
692
693void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
694 VisitCondition(comp);
695}
696
697void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
698 VisitCondition(comp);
699}
700
701void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
702 VisitCondition(comp);
703}
704
705void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
706 VisitCondition(comp);
707}
708
709void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
710 VisitCondition(comp);
711}
712
713void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
714 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000715}
716
717void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000718 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000719}
720
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000721void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
722 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000723}
724
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000725void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100726 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000727}
728
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000729void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100730 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000731}
732
733void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100734 LocationSummary* locations =
735 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100736 switch (store->InputAt(1)->GetType()) {
737 case Primitive::kPrimBoolean:
738 case Primitive::kPrimByte:
739 case Primitive::kPrimChar:
740 case Primitive::kPrimShort:
741 case Primitive::kPrimInt:
742 case Primitive::kPrimNot:
743 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
744 break;
745
746 case Primitive::kPrimLong:
747 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
748 break;
749
750 default:
751 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
752 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000753}
754
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000755void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000756}
757
758void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100759 LocationSummary* locations =
760 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100761 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000762}
763
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000764void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000765}
766
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100767void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100768 LocationSummary* locations =
769 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100770 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100771}
772
773void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
774 // Will be generated at use site.
775}
776
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000777void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000778 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000779}
780
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000781void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
782 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000783}
784
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000785void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100786 LocationSummary* locations =
787 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100788 switch (ret->InputAt(0)->GetType()) {
789 case Primitive::kPrimBoolean:
790 case Primitive::kPrimByte:
791 case Primitive::kPrimChar:
792 case Primitive::kPrimShort:
793 case Primitive::kPrimInt:
794 case Primitive::kPrimNot:
795 locations->SetInAt(0, ArmCoreLocation(R0));
796 break;
797
798 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100799 locations->SetInAt(
800 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100801 break;
802
803 default:
804 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
805 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000806}
807
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000808void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 if (kIsDebugBuild) {
810 switch (ret->InputAt(0)->GetType()) {
811 case Primitive::kPrimBoolean:
812 case Primitive::kPrimByte:
813 case Primitive::kPrimChar:
814 case Primitive::kPrimShort:
815 case Primitive::kPrimInt:
816 case Primitive::kPrimNot:
817 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
818 break;
819
820 case Primitive::kPrimLong:
821 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
822 break;
823
824 default:
825 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
826 }
827 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000828 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000829}
830
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000831void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100832 HandleInvoke(invoke);
833}
834
835void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
836 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
837}
838
839void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
840 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
841 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
842 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
843 invoke->GetIndexInDexCache() * kArmWordSize;
844
845 // TODO: Implement all kinds of calls:
846 // 1) boot -> boot
847 // 2) app -> boot
848 // 3) app -> app
849 //
850 // Currently we implement the app -> app logic, which looks up in the resolve cache.
851
852 // temp = method;
853 LoadCurrentMethod(temp);
854 // temp = temp->dex_cache_resolved_methods_;
855 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
856 // temp = temp[index_in_cache]
857 __ ldr(temp, Address(temp, index_in_cache));
858 // LR = temp[offset_of_quick_compiled_code]
859 __ ldr(LR, Address(temp,
860 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
861 // LR()
862 __ blx(LR);
863
864 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
865 DCHECK(!codegen_->IsLeafMethod());
866}
867
868void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
869 HandleInvoke(invoke);
870}
871
872void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100873 LocationSummary* locations =
874 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100875 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100876
877 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100878 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100879 HInstruction* input = invoke->InputAt(i);
880 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
881 }
882
883 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100884 case Primitive::kPrimBoolean:
885 case Primitive::kPrimByte:
886 case Primitive::kPrimChar:
887 case Primitive::kPrimShort:
888 case Primitive::kPrimInt:
889 case Primitive::kPrimNot:
890 locations->SetOut(ArmCoreLocation(R0));
891 break;
892
893 case Primitive::kPrimLong:
894 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
895 break;
896
897 case Primitive::kPrimVoid:
898 break;
899
900 case Primitive::kPrimDouble:
901 case Primitive::kPrimFloat:
902 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
903 break;
904 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000905}
906
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000907
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100908void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100909 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100910 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
911 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
912 LocationSummary* locations = invoke->GetLocations();
913 Location receiver = locations->InAt(0);
914 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
915 // temp = object->GetClass();
916 if (receiver.IsStackSlot()) {
917 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
918 __ ldr(temp, Address(temp, class_offset));
919 } else {
920 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
921 }
922 // temp = temp->GetMethodAt(method_offset);
923 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
924 __ ldr(temp, Address(temp, method_offset));
925 // LR = temp->GetEntryPoint();
926 __ ldr(LR, Address(temp, entry_point));
927 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000928 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100929 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100930 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000931}
932
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000933void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100934 LocationSummary* locations =
935 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000936 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100937 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100938 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100939 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100940 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100941 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100942 break;
943 }
944
945 case Primitive::kPrimBoolean:
946 case Primitive::kPrimByte:
947 case Primitive::kPrimChar:
948 case Primitive::kPrimShort:
949 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
950 break;
951
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000952 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100953 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000954 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000955}
956
957void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
958 LocationSummary* locations = add->GetLocations();
959 switch (add->GetResultType()) {
960 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100961 if (locations->InAt(1).IsRegister()) {
962 __ add(locations->Out().AsArm().AsCoreRegister(),
963 locations->InAt(0).AsArm().AsCoreRegister(),
964 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
965 } else {
966 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
967 locations->InAt(0).AsArm().AsCoreRegister(),
968 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
969 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000970 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100971
972 case Primitive::kPrimLong:
973 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
974 locations->InAt(0).AsArm().AsRegisterPairLow(),
975 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
976 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
977 locations->InAt(0).AsArm().AsRegisterPairHigh(),
978 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
979 break;
980
981 case Primitive::kPrimBoolean:
982 case Primitive::kPrimByte:
983 case Primitive::kPrimChar:
984 case Primitive::kPrimShort:
985 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
986 break;
987
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000988 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100989 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000990 }
991}
992
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100993void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100994 LocationSummary* locations =
995 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100996 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100997 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100998 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100999 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001000 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001001 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001002 break;
1003 }
1004
1005 case Primitive::kPrimBoolean:
1006 case Primitive::kPrimByte:
1007 case Primitive::kPrimChar:
1008 case Primitive::kPrimShort:
1009 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1010 break;
1011
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001012 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001013 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001014 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001015}
1016
1017void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1018 LocationSummary* locations = sub->GetLocations();
1019 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001020 case Primitive::kPrimInt: {
1021 if (locations->InAt(1).IsRegister()) {
1022 __ sub(locations->Out().AsArm().AsCoreRegister(),
1023 locations->InAt(0).AsArm().AsCoreRegister(),
1024 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1025 } else {
1026 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1027 locations->InAt(0).AsArm().AsCoreRegister(),
1028 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1029 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001030 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001032
1033 case Primitive::kPrimLong:
1034 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1035 locations->InAt(0).AsArm().AsRegisterPairLow(),
1036 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1037 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1038 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1039 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1040 break;
1041
1042 case Primitive::kPrimBoolean:
1043 case Primitive::kPrimByte:
1044 case Primitive::kPrimChar:
1045 case Primitive::kPrimShort:
1046 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1047 break;
1048
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001049 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001050 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001051 }
1052}
1053
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001054void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001055 LocationSummary* locations =
1056 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001057 InvokeRuntimeCallingConvention calling_convention;
1058 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1059 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001060 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001061}
1062
1063void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1064 InvokeRuntimeCallingConvention calling_convention;
1065 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1066 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1067
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001068 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001069 __ ldr(LR, Address(TR, offset));
1070 __ blx(LR);
1071
Nicolas Geoffray39468442014-09-02 15:17:15 +01001072 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001073 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001074}
1075
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001076void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001077 LocationSummary* locations =
1078 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001079 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1080 if (location.IsStackSlot()) {
1081 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1082 } else if (location.IsDoubleStackSlot()) {
1083 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001084 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001085 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001086}
1087
1088void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001089 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001090}
1091
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001092void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001093 LocationSummary* locations =
1094 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001095 locations->SetInAt(0, Location::RequiresRegister());
1096 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001097}
1098
1099void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1100 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001101 __ eor(locations->Out().AsArm().AsCoreRegister(),
1102 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001103}
1104
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001105void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001106 LocationSummary* locations =
1107 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001108 locations->SetInAt(0, Location::RequiresRegister());
1109 locations->SetInAt(1, Location::RequiresRegister());
1110 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001111}
1112
1113void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1114 Label greater, done;
1115 LocationSummary* locations = compare->GetLocations();
1116 switch (compare->InputAt(0)->GetType()) {
1117 case Primitive::kPrimLong: {
1118 Register output = locations->Out().AsArm().AsCoreRegister();
1119 ArmManagedRegister left = locations->InAt(0).AsArm();
1120 ArmManagedRegister right = locations->InAt(1).AsArm();
1121 Label less, greater, done;
1122 __ cmp(left.AsRegisterPairHigh(),
1123 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1124 __ b(&less, LT);
1125 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001126 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1127 // the status flags.
1128 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001129 __ cmp(left.AsRegisterPairLow(),
1130 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001131 __ b(&done, EQ);
1132 __ b(&less, CC);
1133
1134 __ Bind(&greater);
1135 __ LoadImmediate(output, 1);
1136 __ b(&done);
1137
1138 __ Bind(&less);
1139 __ LoadImmediate(output, -1);
1140
1141 __ Bind(&done);
1142 break;
1143 }
1144 default:
1145 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1146 }
1147}
1148
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001149void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001150 LocationSummary* locations =
1151 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001152 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1153 locations->SetInAt(i, Location::Any());
1154 }
1155 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001156}
1157
1158void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001159 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001160}
1161
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001162void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001163 LocationSummary* locations =
1164 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001165 locations->SetInAt(0, Location::RequiresRegister());
1166 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001167 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001168 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001169 locations->AddTemp(Location::RequiresRegister());
1170 locations->AddTemp(Location::RequiresRegister());
1171 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001172}
1173
1174void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1175 LocationSummary* locations = instruction->GetLocations();
1176 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1177 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001178 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001179
1180 switch (field_type) {
1181 case Primitive::kPrimBoolean:
1182 case Primitive::kPrimByte: {
1183 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1184 __ StoreToOffset(kStoreByte, value, obj, offset);
1185 break;
1186 }
1187
1188 case Primitive::kPrimShort:
1189 case Primitive::kPrimChar: {
1190 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1191 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1192 break;
1193 }
1194
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001195 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001196 case Primitive::kPrimNot: {
1197 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1198 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001199 if (field_type == Primitive::kPrimNot) {
1200 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1201 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1202 codegen_->MarkGCCard(temp, card, obj, value);
1203 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001204 break;
1205 }
1206
1207 case Primitive::kPrimLong: {
1208 ArmManagedRegister value = locations->InAt(1).AsArm();
1209 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1210 break;
1211 }
1212
1213 case Primitive::kPrimFloat:
1214 case Primitive::kPrimDouble:
1215 LOG(FATAL) << "Unimplemented register type " << field_type;
1216
1217 case Primitive::kPrimVoid:
1218 LOG(FATAL) << "Unreachable type " << field_type;
1219 }
1220}
1221
1222void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001223 LocationSummary* locations =
1224 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001225 locations->SetInAt(0, Location::RequiresRegister());
1226 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001227}
1228
1229void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1230 LocationSummary* locations = instruction->GetLocations();
1231 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1232 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1233
1234 switch (instruction->GetType()) {
1235 case Primitive::kPrimBoolean: {
1236 Register out = locations->Out().AsArm().AsCoreRegister();
1237 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1238 break;
1239 }
1240
1241 case Primitive::kPrimByte: {
1242 Register out = locations->Out().AsArm().AsCoreRegister();
1243 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1244 break;
1245 }
1246
1247 case Primitive::kPrimShort: {
1248 Register out = locations->Out().AsArm().AsCoreRegister();
1249 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1250 break;
1251 }
1252
1253 case Primitive::kPrimChar: {
1254 Register out = locations->Out().AsArm().AsCoreRegister();
1255 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1256 break;
1257 }
1258
1259 case Primitive::kPrimInt:
1260 case Primitive::kPrimNot: {
1261 Register out = locations->Out().AsArm().AsCoreRegister();
1262 __ LoadFromOffset(kLoadWord, out, obj, offset);
1263 break;
1264 }
1265
1266 case Primitive::kPrimLong: {
1267 // TODO: support volatile.
1268 ArmManagedRegister out = locations->Out().AsArm();
1269 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1270 break;
1271 }
1272
1273 case Primitive::kPrimFloat:
1274 case Primitive::kPrimDouble:
1275 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1276
1277 case Primitive::kPrimVoid:
1278 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1279 }
1280}
1281
1282void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001283 LocationSummary* locations =
1284 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001285 locations->SetInAt(0, Location::RequiresRegister());
1286 // TODO: Have a normalization phase that makes this instruction never used.
1287 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001288}
1289
1290void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001291 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001292 codegen_->AddSlowPath(slow_path);
1293
1294 LocationSummary* locations = instruction->GetLocations();
1295 Location obj = locations->InAt(0);
1296 DCHECK(obj.Equals(locations->Out()));
1297
1298 if (obj.IsRegister()) {
1299 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1300 }
1301 __ b(slow_path->GetEntryLabel(), EQ);
1302}
1303
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001304void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001305 LocationSummary* locations =
1306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001307 locations->SetInAt(0, Location::RequiresRegister());
1308 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1309 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001310}
1311
1312void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1313 LocationSummary* locations = instruction->GetLocations();
1314 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1315 Location index = locations->InAt(1);
1316
1317 switch (instruction->GetType()) {
1318 case Primitive::kPrimBoolean: {
1319 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1320 Register out = locations->Out().AsArm().AsCoreRegister();
1321 if (index.IsConstant()) {
1322 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1323 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1324 } else {
1325 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1326 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1327 }
1328 break;
1329 }
1330
1331 case Primitive::kPrimByte: {
1332 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1333 Register out = locations->Out().AsArm().AsCoreRegister();
1334 if (index.IsConstant()) {
1335 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1336 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1337 } else {
1338 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1339 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1340 }
1341 break;
1342 }
1343
1344 case Primitive::kPrimShort: {
1345 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1346 Register out = locations->Out().AsArm().AsCoreRegister();
1347 if (index.IsConstant()) {
1348 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1349 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1350 } else {
1351 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1352 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1353 }
1354 break;
1355 }
1356
1357 case Primitive::kPrimChar: {
1358 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1359 Register out = locations->Out().AsArm().AsCoreRegister();
1360 if (index.IsConstant()) {
1361 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1362 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1363 } else {
1364 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1365 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1366 }
1367 break;
1368 }
1369
1370 case Primitive::kPrimInt:
1371 case Primitive::kPrimNot: {
1372 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1373 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1374 Register out = locations->Out().AsArm().AsCoreRegister();
1375 if (index.IsConstant()) {
1376 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1377 __ LoadFromOffset(kLoadWord, out, obj, offset);
1378 } else {
1379 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1380 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1381 }
1382 break;
1383 }
1384
1385 case Primitive::kPrimLong: {
1386 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1387 ArmManagedRegister out = locations->Out().AsArm();
1388 if (index.IsConstant()) {
1389 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1390 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1391 } else {
1392 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1393 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1394 }
1395 break;
1396 }
1397
1398 case Primitive::kPrimFloat:
1399 case Primitive::kPrimDouble:
1400 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1401
1402 case Primitive::kPrimVoid:
1403 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1404 }
1405}
1406
1407void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001408 Primitive::Type value_type = instruction->GetComponentType();
1409 bool is_object = value_type == Primitive::kPrimNot;
1410 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1411 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1412 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001413 InvokeRuntimeCallingConvention calling_convention;
1414 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1415 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1416 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001417 } else {
1418 locations->SetInAt(0, Location::RequiresRegister());
1419 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1420 locations->SetInAt(2, Location::RequiresRegister());
1421 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001422}
1423
1424void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1425 LocationSummary* locations = instruction->GetLocations();
1426 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1427 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001428 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001429
1430 switch (value_type) {
1431 case Primitive::kPrimBoolean:
1432 case Primitive::kPrimByte: {
1433 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1434 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1435 if (index.IsConstant()) {
1436 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1437 __ StoreToOffset(kStoreByte, value, obj, offset);
1438 } else {
1439 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1440 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1441 }
1442 break;
1443 }
1444
1445 case Primitive::kPrimShort:
1446 case Primitive::kPrimChar: {
1447 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1448 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1449 if (index.IsConstant()) {
1450 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1451 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1452 } else {
1453 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1454 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1455 }
1456 break;
1457 }
1458
1459 case Primitive::kPrimInt: {
1460 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1461 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1462 if (index.IsConstant()) {
1463 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1464 __ StoreToOffset(kStoreWord, value, obj, offset);
1465 } else {
1466 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1467 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1468 }
1469 break;
1470 }
1471
1472 case Primitive::kPrimNot: {
1473 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1474 __ ldr(LR, Address(TR, offset));
1475 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001476 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001477 DCHECK(!codegen_->IsLeafMethod());
1478 break;
1479 }
1480
1481 case Primitive::kPrimLong: {
1482 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1483 ArmManagedRegister value = locations->InAt(2).AsArm();
1484 if (index.IsConstant()) {
1485 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1486 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1487 } else {
1488 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1489 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1490 }
1491 break;
1492 }
1493
1494 case Primitive::kPrimFloat:
1495 case Primitive::kPrimDouble:
1496 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1497
1498 case Primitive::kPrimVoid:
1499 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1500 }
1501}
1502
1503void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001504 LocationSummary* locations =
1505 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001506 locations->SetInAt(0, Location::RequiresRegister());
1507 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001508}
1509
1510void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1511 LocationSummary* locations = instruction->GetLocations();
1512 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1513 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1514 Register out = locations->Out().AsArm().AsCoreRegister();
1515 __ LoadFromOffset(kLoadWord, out, obj, offset);
1516}
1517
1518void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001519 LocationSummary* locations =
1520 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001521 locations->SetInAt(0, Location::RequiresRegister());
1522 locations->SetInAt(1, Location::RequiresRegister());
1523 // TODO: Have a normalization phase that makes this instruction never used.
1524 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001525}
1526
1527void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1528 LocationSummary* locations = instruction->GetLocations();
1529 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001530 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001531 codegen_->AddSlowPath(slow_path);
1532
1533 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1534 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1535
1536 __ cmp(index, ShifterOperand(length));
1537 __ b(slow_path->GetEntryLabel(), CS);
1538}
1539
1540void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1541 Label is_null;
1542 __ CompareAndBranchIfZero(value, &is_null);
1543 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1544 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1545 __ strb(card, Address(card, temp));
1546 __ Bind(&is_null);
1547}
1548
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001549void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1550 temp->SetLocations(nullptr);
1551}
1552
1553void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1554 // Nothing to do, this is driven by the code generator.
1555}
1556
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001557void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001558 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001559}
1560
1561void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001562 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1563}
1564
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001565void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1566 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1567}
1568
1569void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1570 SuspendCheckSlowPathARM* slow_path =
1571 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction);
1572 codegen_->AddSlowPath(slow_path);
1573
1574 __ AddConstant(R4, R4, -1);
1575 __ cmp(R4, ShifterOperand(0));
1576 __ b(slow_path->GetEntryLabel(), LE);
1577 __ Bind(slow_path->GetReturnLabel());
1578}
1579
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001580ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1581 return codegen_->GetAssembler();
1582}
1583
1584void ParallelMoveResolverARM::EmitMove(size_t index) {
1585 MoveOperands* move = moves_.Get(index);
1586 Location source = move->GetSource();
1587 Location destination = move->GetDestination();
1588
1589 if (source.IsRegister()) {
1590 if (destination.IsRegister()) {
1591 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1592 } else {
1593 DCHECK(destination.IsStackSlot());
1594 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1595 SP, destination.GetStackIndex());
1596 }
1597 } else if (source.IsStackSlot()) {
1598 if (destination.IsRegister()) {
1599 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1600 SP, source.GetStackIndex());
1601 } else {
1602 DCHECK(destination.IsStackSlot());
1603 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1604 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1605 }
1606 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001607 DCHECK(source.IsConstant());
1608 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1609 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1610 if (destination.IsRegister()) {
1611 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1612 } else {
1613 DCHECK(destination.IsStackSlot());
1614 __ LoadImmediate(IP, value);
1615 __ str(IP, Address(SP, destination.GetStackIndex()));
1616 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001617 }
1618}
1619
1620void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1621 __ Mov(IP, reg);
1622 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1623 __ StoreToOffset(kStoreWord, IP, SP, mem);
1624}
1625
1626void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1627 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1628 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1629 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1630 SP, mem1 + stack_offset);
1631 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1632 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1633 SP, mem2 + stack_offset);
1634 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1635}
1636
1637void ParallelMoveResolverARM::EmitSwap(size_t index) {
1638 MoveOperands* move = moves_.Get(index);
1639 Location source = move->GetSource();
1640 Location destination = move->GetDestination();
1641
1642 if (source.IsRegister() && destination.IsRegister()) {
1643 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1644 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1645 __ Mov(IP, source.AsArm().AsCoreRegister());
1646 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1647 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1648 } else if (source.IsRegister() && destination.IsStackSlot()) {
1649 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1650 } else if (source.IsStackSlot() && destination.IsRegister()) {
1651 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1652 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1653 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1654 } else {
1655 LOG(FATAL) << "Unimplemented";
1656 }
1657}
1658
1659void ParallelMoveResolverARM::SpillScratch(int reg) {
1660 __ Push(static_cast<Register>(reg));
1661}
1662
1663void ParallelMoveResolverARM::RestoreScratch(int reg) {
1664 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001665}
1666
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001667} // namespace arm
1668} // namespace art