blob: ad622798a62102694d4cac441c4c06f7598b559f [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());
101 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
102 __ ldr(LR, Address(TR, offset));
103 __ blx(LR);
104 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
105 __ b(GetReturnLabel());
106 }
107
108 Label* GetReturnLabel() { return &return_label_; }
109
110 private:
111 HSuspendCheck* const instruction_;
112 Label return_label_;
113
114 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
115};
116
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100117class BoundsCheckSlowPathARM : public SlowPathCode {
118 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100119 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100120 Location index_location,
121 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100122 : instruction_(instruction),
123 index_location_(index_location),
124 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100125
126 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
127 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
128 __ Bind(GetEntryLabel());
129 InvokeRuntimeCallingConvention calling_convention;
130 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
131 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
132 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
133 __ ldr(LR, Address(TR, offset));
134 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100135 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100136 }
137
138 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100139 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140 const Location index_location_;
141 const Location length_location_;
142
143 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
144};
145
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100146#undef __
147#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700148
149inline Condition ARMCondition(IfCondition cond) {
150 switch (cond) {
151 case kCondEQ: return EQ;
152 case kCondNE: return NE;
153 case kCondLT: return LT;
154 case kCondLE: return LE;
155 case kCondGT: return GT;
156 case kCondGE: return GE;
157 default:
158 LOG(FATAL) << "Unknown if condition";
159 }
160 return EQ; // Unreachable.
161}
162
163inline Condition ARMOppositeCondition(IfCondition cond) {
164 switch (cond) {
165 case kCondEQ: return NE;
166 case kCondNE: return EQ;
167 case kCondLT: return GE;
168 case kCondLE: return GT;
169 case kCondGT: return LE;
170 case kCondGE: return LT;
171 default:
172 LOG(FATAL) << "Unknown if condition";
173 }
174 return EQ; // Unreachable.
175}
176
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100177void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
178 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
179}
180
181void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
182 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
183}
184
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100185CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
186 : CodeGenerator(graph, kNumberOfRegIds),
187 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100188 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100189 move_resolver_(graph->GetArena(), this),
190 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100191
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100192size_t CodeGeneratorARM::FrameEntrySpillSize() const {
193 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
194}
195
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100196static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
197 return blocked_registers + kNumberOfAllocIds;
198}
199
200ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
201 bool* blocked_registers) const {
202 switch (type) {
203 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100204 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
205 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100206 ArmManagedRegister pair =
207 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
208 blocked_registers[pair.AsRegisterPairLow()] = true;
209 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100210 // Block all other register pairs that share a register with `pair`.
211 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
212 ArmManagedRegister current =
213 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
214 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
215 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
216 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
217 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
218 blocked_register_pairs[i] = true;
219 }
220 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100221 return pair;
222 }
223
224 case Primitive::kPrimByte:
225 case Primitive::kPrimBoolean:
226 case Primitive::kPrimChar:
227 case Primitive::kPrimShort:
228 case Primitive::kPrimInt:
229 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100230 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
231 // Block all register pairs that contain `reg`.
232 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
233 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
234 ArmManagedRegister current =
235 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
236 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
237 blocked_register_pairs[i] = true;
238 }
239 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100240 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
241 }
242
243 case Primitive::kPrimFloat:
244 case Primitive::kPrimDouble:
245 LOG(FATAL) << "Unimplemented register type " << type;
246
247 case Primitive::kPrimVoid:
248 LOG(FATAL) << "Unreachable type " << type;
249 }
250
251 return ManagedRegister::NoRegister();
252}
253
254void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
255 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
256
257 // Don't allocate the dalvik style register pair passing.
258 blocked_register_pairs[R1_R2] = true;
259
260 // Stack register, LR and PC are always reserved.
261 blocked_registers[SP] = true;
262 blocked_registers[LR] = true;
263 blocked_registers[PC] = true;
264
265 // Reserve R4 for suspend check.
266 blocked_registers[R4] = true;
267 blocked_register_pairs[R4_R5] = true;
268
269 // Reserve thread register.
270 blocked_registers[TR] = true;
271
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100272 // Reserve temp register.
273 blocked_registers[IP] = true;
274
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100275 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100276 // We always save and restore R6 and R7 to make sure we can use three
277 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100278 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100279 blocked_registers[R8] = true;
280 blocked_registers[R10] = true;
281 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100282}
283
284size_t CodeGeneratorARM::GetNumberOfRegisters() const {
285 return kNumberOfRegIds;
286}
287
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100288InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
289 : HGraphVisitor(graph),
290 assembler_(codegen->GetAssembler()),
291 codegen_(codegen) {}
292
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000293void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700294 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100295 if (!skip_overflow_check) {
296 if (kExplicitStackOverflowCheck) {
297 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
298 AddSlowPath(slow_path);
299
300 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
301 __ cmp(SP, ShifterOperand(IP));
302 __ b(slow_path->GetEntryLabel(), CC);
303 } else {
304 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
305 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100306 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100307 }
308 }
309
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100310 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
311 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000312
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100313 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100314 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000315 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000316}
317
318void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100319 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100320 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000321}
322
323void CodeGeneratorARM::Bind(Label* label) {
324 __ Bind(label);
325}
326
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100327Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
328 switch (load->GetType()) {
329 case Primitive::kPrimLong:
330 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
331 break;
332
333 case Primitive::kPrimInt:
334 case Primitive::kPrimNot:
335 return Location::StackSlot(GetStackSlot(load->GetLocal()));
336
337 case Primitive::kPrimFloat:
338 case Primitive::kPrimDouble:
339 LOG(FATAL) << "Unimplemented type " << load->GetType();
340
341 case Primitive::kPrimBoolean:
342 case Primitive::kPrimByte:
343 case Primitive::kPrimChar:
344 case Primitive::kPrimShort:
345 case Primitive::kPrimVoid:
346 LOG(FATAL) << "Unexpected type " << load->GetType();
347 }
348
349 LOG(FATAL) << "Unreachable";
350 return Location();
351}
352
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100353Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
354 switch (type) {
355 case Primitive::kPrimBoolean:
356 case Primitive::kPrimByte:
357 case Primitive::kPrimChar:
358 case Primitive::kPrimShort:
359 case Primitive::kPrimInt:
360 case Primitive::kPrimNot: {
361 uint32_t index = gp_index_++;
362 if (index < calling_convention.GetNumberOfRegisters()) {
363 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
364 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100365 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100366 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100367 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100368
369 case Primitive::kPrimLong: {
370 uint32_t index = gp_index_;
371 gp_index_ += 2;
372 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
373 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
374 calling_convention.GetRegisterPairAt(index)));
375 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
376 return Location::QuickParameter(index);
377 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100378 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100379 }
380 }
381
382 case Primitive::kPrimDouble:
383 case Primitive::kPrimFloat:
384 LOG(FATAL) << "Unimplemented parameter type " << type;
385 break;
386
387 case Primitive::kPrimVoid:
388 LOG(FATAL) << "Unexpected parameter type " << type;
389 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100390 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100391 return Location();
392}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100393
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100394void CodeGeneratorARM::Move32(Location destination, Location source) {
395 if (source.Equals(destination)) {
396 return;
397 }
398 if (destination.IsRegister()) {
399 if (source.IsRegister()) {
400 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
401 } else {
402 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
403 }
404 } else {
405 DCHECK(destination.IsStackSlot());
406 if (source.IsRegister()) {
407 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
408 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100409 __ ldr(IP, Address(SP, source.GetStackIndex()));
410 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100411 }
412 }
413}
414
415void CodeGeneratorARM::Move64(Location destination, Location source) {
416 if (source.Equals(destination)) {
417 return;
418 }
419 if (destination.IsRegister()) {
420 if (source.IsRegister()) {
421 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
422 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
423 } else if (source.IsQuickParameter()) {
424 uint32_t argument_index = source.GetQuickParameterIndex();
425 InvokeDexCallingConvention calling_convention;
426 __ Mov(destination.AsArm().AsRegisterPairLow(),
427 calling_convention.GetRegisterAt(argument_index));
428 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100429 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100430 } else {
431 DCHECK(source.IsDoubleStackSlot());
432 if (destination.AsArm().AsRegisterPair() == R1_R2) {
433 __ ldr(R1, Address(SP, source.GetStackIndex()));
434 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
435 } else {
436 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
437 SP, source.GetStackIndex());
438 }
439 }
440 } else if (destination.IsQuickParameter()) {
441 InvokeDexCallingConvention calling_convention;
442 uint32_t argument_index = destination.GetQuickParameterIndex();
443 if (source.IsRegister()) {
444 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
445 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100446 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100447 } else {
448 DCHECK(source.IsDoubleStackSlot());
449 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100450 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
451 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100452 }
453 } else {
454 DCHECK(destination.IsDoubleStackSlot());
455 if (source.IsRegister()) {
456 if (source.AsArm().AsRegisterPair() == R1_R2) {
457 __ str(R1, Address(SP, destination.GetStackIndex()));
458 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
459 } else {
460 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
461 SP, destination.GetStackIndex());
462 }
463 } else if (source.IsQuickParameter()) {
464 InvokeDexCallingConvention calling_convention;
465 uint32_t argument_index = source.GetQuickParameterIndex();
466 __ str(calling_convention.GetRegisterAt(argument_index),
467 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100468 __ ldr(R0,
469 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
470 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100471 } else {
472 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100473 __ ldr(IP, Address(SP, source.GetStackIndex()));
474 __ str(IP, Address(SP, destination.GetStackIndex()));
475 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
476 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100477 }
478 }
479}
480
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100481void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100482 LocationSummary* locations = instruction->GetLocations();
483 if (locations != nullptr && locations->Out().Equals(location)) {
484 return;
485 }
486
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100487 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100488 int32_t value = instruction->AsIntConstant()->GetValue();
489 if (location.IsRegister()) {
490 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
491 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100492 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100493 __ LoadImmediate(IP, value);
494 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100495 }
496 } else if (instruction->AsLongConstant() != nullptr) {
497 int64_t value = instruction->AsLongConstant()->GetValue();
498 if (location.IsRegister()) {
499 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
500 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
501 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100502 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100503 __ LoadImmediate(IP, Low32Bits(value));
504 __ str(IP, Address(SP, location.GetStackIndex()));
505 __ LoadImmediate(IP, High32Bits(value));
506 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100507 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100508 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100509 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
510 switch (instruction->GetType()) {
511 case Primitive::kPrimBoolean:
512 case Primitive::kPrimByte:
513 case Primitive::kPrimChar:
514 case Primitive::kPrimShort:
515 case Primitive::kPrimInt:
516 case Primitive::kPrimNot:
517 Move32(location, Location::StackSlot(stack_slot));
518 break;
519
520 case Primitive::kPrimLong:
521 Move64(location, Location::DoubleStackSlot(stack_slot));
522 break;
523
524 default:
525 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
526 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000527 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100528 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100529 switch (instruction->GetType()) {
530 case Primitive::kPrimBoolean:
531 case Primitive::kPrimByte:
532 case Primitive::kPrimChar:
533 case Primitive::kPrimShort:
534 case Primitive::kPrimNot:
535 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100536 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100537 break;
538
539 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100540 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100541 break;
542
543 default:
544 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
545 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000546 }
547}
548
549void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000550 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000551}
552
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000553void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000554 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000555 if (GetGraph()->GetExitBlock() == successor) {
556 codegen_->GenerateFrameExit();
557 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
558 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000559 }
560}
561
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000562void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000563 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000564}
565
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000566void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000567 if (kIsDebugBuild) {
568 __ Comment("Unreachable");
569 __ bkpt(0);
570 }
571}
572
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000573void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100574 LocationSummary* locations =
575 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100576 HInstruction* cond = if_instr->InputAt(0);
577 DCHECK(cond->IsCondition());
578 HCondition* condition = cond->AsCondition();
579 if (condition->NeedsMaterialization()) {
580 locations->SetInAt(0, Location::Any());
581 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000582}
583
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000584void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700585 HInstruction* cond = if_instr->InputAt(0);
586 DCHECK(cond->IsCondition());
587 HCondition* condition = cond->AsCondition();
588 if (condition->NeedsMaterialization()) {
589 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100590 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700591 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
592 ShifterOperand(0));
593 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
594 } else {
595 // Condition has not been materialized, use its inputs as the comparison and its
596 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100597 LocationSummary* locations = condition->GetLocations();
598 if (locations->InAt(1).IsRegister()) {
599 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
600 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
601 } else {
602 DCHECK(locations->InAt(1).IsConstant());
603 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
604 ShifterOperand operand;
605 if (ShifterOperand::CanHoldArm(value, &operand)) {
606 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
607 } else {
608 Register temp = IP;
609 __ LoadImmediate(temp, value);
610 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
611 }
612 }
Dave Allison20dfc792014-06-16 20:44:29 -0700613 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
614 ARMCondition(condition->GetCondition()));
615 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100616
Dave Allison20dfc792014-06-16 20:44:29 -0700617 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
618 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000619 }
620}
621
Dave Allison20dfc792014-06-16 20:44:29 -0700622
623void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100624 LocationSummary* locations =
625 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100626 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100627 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100628 if (comp->NeedsMaterialization()) {
629 locations->SetOut(Location::RequiresRegister());
630 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000631}
632
Dave Allison20dfc792014-06-16 20:44:29 -0700633void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100634 if (!comp->NeedsMaterialization()) return;
635
636 LocationSummary* locations = comp->GetLocations();
637 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700638 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
639 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100640 } else {
641 DCHECK(locations->InAt(1).IsConstant());
642 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
643 ShifterOperand operand;
644 if (ShifterOperand::CanHoldArm(value, &operand)) {
645 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
646 } else {
647 Register temp = IP;
648 __ LoadImmediate(temp, value);
649 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
650 }
Dave Allison20dfc792014-06-16 20:44:29 -0700651 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100652 __ it(ARMCondition(comp->GetCondition()), kItElse);
653 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
654 ARMCondition(comp->GetCondition()));
655 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
656 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700657}
658
659void LocationsBuilderARM::VisitEqual(HEqual* comp) {
660 VisitCondition(comp);
661}
662
663void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
664 VisitCondition(comp);
665}
666
667void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
668 VisitCondition(comp);
669}
670
671void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
672 VisitCondition(comp);
673}
674
675void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
676 VisitCondition(comp);
677}
678
679void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
680 VisitCondition(comp);
681}
682
683void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
684 VisitCondition(comp);
685}
686
687void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
688 VisitCondition(comp);
689}
690
691void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
692 VisitCondition(comp);
693}
694
695void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
696 VisitCondition(comp);
697}
698
699void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
700 VisitCondition(comp);
701}
702
703void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
704 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000705}
706
707void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000708 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000709}
710
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000711void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
712 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000713}
714
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000715void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100716 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000717}
718
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000719void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100720 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000721}
722
723void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100724 LocationSummary* locations =
725 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100726 switch (store->InputAt(1)->GetType()) {
727 case Primitive::kPrimBoolean:
728 case Primitive::kPrimByte:
729 case Primitive::kPrimChar:
730 case Primitive::kPrimShort:
731 case Primitive::kPrimInt:
732 case Primitive::kPrimNot:
733 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
734 break;
735
736 case Primitive::kPrimLong:
737 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
738 break;
739
740 default:
741 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
742 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000743}
744
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000745void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000746}
747
748void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100749 LocationSummary* locations =
750 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100751 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000752}
753
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000754void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000755}
756
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100757void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100758 LocationSummary* locations =
759 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100760 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100761}
762
763void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
764 // Will be generated at use site.
765}
766
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000767void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000768 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000769}
770
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000771void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
772 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000773}
774
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000775void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100776 LocationSummary* locations =
777 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100778 switch (ret->InputAt(0)->GetType()) {
779 case Primitive::kPrimBoolean:
780 case Primitive::kPrimByte:
781 case Primitive::kPrimChar:
782 case Primitive::kPrimShort:
783 case Primitive::kPrimInt:
784 case Primitive::kPrimNot:
785 locations->SetInAt(0, ArmCoreLocation(R0));
786 break;
787
788 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100789 locations->SetInAt(
790 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100791 break;
792
793 default:
794 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
795 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000796}
797
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000798void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100799 if (kIsDebugBuild) {
800 switch (ret->InputAt(0)->GetType()) {
801 case Primitive::kPrimBoolean:
802 case Primitive::kPrimByte:
803 case Primitive::kPrimChar:
804 case Primitive::kPrimShort:
805 case Primitive::kPrimInt:
806 case Primitive::kPrimNot:
807 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
808 break;
809
810 case Primitive::kPrimLong:
811 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
812 break;
813
814 default:
815 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
816 }
817 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000818 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000819}
820
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000821void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100822 HandleInvoke(invoke);
823}
824
825void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
826 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
827}
828
829void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
830 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
831 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
832 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
833 invoke->GetIndexInDexCache() * kArmWordSize;
834
835 // TODO: Implement all kinds of calls:
836 // 1) boot -> boot
837 // 2) app -> boot
838 // 3) app -> app
839 //
840 // Currently we implement the app -> app logic, which looks up in the resolve cache.
841
842 // temp = method;
843 LoadCurrentMethod(temp);
844 // temp = temp->dex_cache_resolved_methods_;
845 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
846 // temp = temp[index_in_cache]
847 __ ldr(temp, Address(temp, index_in_cache));
848 // LR = temp[offset_of_quick_compiled_code]
849 __ ldr(LR, Address(temp,
850 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
851 // LR()
852 __ blx(LR);
853
854 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
855 DCHECK(!codegen_->IsLeafMethod());
856}
857
858void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
859 HandleInvoke(invoke);
860}
861
862void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100863 LocationSummary* locations =
864 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100865 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100866
867 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100868 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100869 HInstruction* input = invoke->InputAt(i);
870 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
871 }
872
873 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 case Primitive::kPrimBoolean:
875 case Primitive::kPrimByte:
876 case Primitive::kPrimChar:
877 case Primitive::kPrimShort:
878 case Primitive::kPrimInt:
879 case Primitive::kPrimNot:
880 locations->SetOut(ArmCoreLocation(R0));
881 break;
882
883 case Primitive::kPrimLong:
884 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
885 break;
886
887 case Primitive::kPrimVoid:
888 break;
889
890 case Primitive::kPrimDouble:
891 case Primitive::kPrimFloat:
892 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
893 break;
894 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000895}
896
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000897
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100898void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100899 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100900 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
901 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
902 LocationSummary* locations = invoke->GetLocations();
903 Location receiver = locations->InAt(0);
904 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
905 // temp = object->GetClass();
906 if (receiver.IsStackSlot()) {
907 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
908 __ ldr(temp, Address(temp, class_offset));
909 } else {
910 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
911 }
912 // temp = temp->GetMethodAt(method_offset);
913 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
914 __ ldr(temp, Address(temp, method_offset));
915 // LR = temp->GetEntryPoint();
916 __ ldr(LR, Address(temp, entry_point));
917 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000918 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100919 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100920 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000921}
922
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000923void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100924 LocationSummary* locations =
925 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000926 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100927 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100928 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100929 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100930 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100931 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100932 break;
933 }
934
935 case Primitive::kPrimBoolean:
936 case Primitive::kPrimByte:
937 case Primitive::kPrimChar:
938 case Primitive::kPrimShort:
939 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
940 break;
941
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000942 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100943 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000944 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000945}
946
947void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
948 LocationSummary* locations = add->GetLocations();
949 switch (add->GetResultType()) {
950 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100951 if (locations->InAt(1).IsRegister()) {
952 __ add(locations->Out().AsArm().AsCoreRegister(),
953 locations->InAt(0).AsArm().AsCoreRegister(),
954 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
955 } else {
956 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
957 locations->InAt(0).AsArm().AsCoreRegister(),
958 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
959 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000960 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100961
962 case Primitive::kPrimLong:
963 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
964 locations->InAt(0).AsArm().AsRegisterPairLow(),
965 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
966 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
967 locations->InAt(0).AsArm().AsRegisterPairHigh(),
968 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
969 break;
970
971 case Primitive::kPrimBoolean:
972 case Primitive::kPrimByte:
973 case Primitive::kPrimChar:
974 case Primitive::kPrimShort:
975 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
976 break;
977
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000978 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100979 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000980 }
981}
982
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100983void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100984 LocationSummary* locations =
985 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100986 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100987 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100988 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100989 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100990 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100991 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100992 break;
993 }
994
995 case Primitive::kPrimBoolean:
996 case Primitive::kPrimByte:
997 case Primitive::kPrimChar:
998 case Primitive::kPrimShort:
999 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1000 break;
1001
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001002 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001003 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001004 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001005}
1006
1007void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1008 LocationSummary* locations = sub->GetLocations();
1009 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001010 case Primitive::kPrimInt: {
1011 if (locations->InAt(1).IsRegister()) {
1012 __ sub(locations->Out().AsArm().AsCoreRegister(),
1013 locations->InAt(0).AsArm().AsCoreRegister(),
1014 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1015 } else {
1016 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1017 locations->InAt(0).AsArm().AsCoreRegister(),
1018 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1019 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001020 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001021 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001022
1023 case Primitive::kPrimLong:
1024 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1025 locations->InAt(0).AsArm().AsRegisterPairLow(),
1026 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1027 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1028 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1029 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1030 break;
1031
1032 case Primitive::kPrimBoolean:
1033 case Primitive::kPrimByte:
1034 case Primitive::kPrimChar:
1035 case Primitive::kPrimShort:
1036 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1037 break;
1038
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001039 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001040 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001041 }
1042}
1043
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001044void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001045 LocationSummary* locations =
1046 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001047 InvokeRuntimeCallingConvention calling_convention;
1048 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1049 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001050 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001051}
1052
1053void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1054 InvokeRuntimeCallingConvention calling_convention;
1055 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1056 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1057
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001058 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001059 __ ldr(LR, Address(TR, offset));
1060 __ blx(LR);
1061
Nicolas Geoffray39468442014-09-02 15:17:15 +01001062 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001063 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001064}
1065
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001066void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001067 LocationSummary* locations =
1068 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001069 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1070 if (location.IsStackSlot()) {
1071 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1072 } else if (location.IsDoubleStackSlot()) {
1073 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001074 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001075 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001076}
1077
1078void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001079 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001080}
1081
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001082void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001083 LocationSummary* locations =
1084 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001085 locations->SetInAt(0, Location::RequiresRegister());
1086 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001087}
1088
1089void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1090 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001091 __ eor(locations->Out().AsArm().AsCoreRegister(),
1092 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001093}
1094
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001095void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001096 LocationSummary* locations =
1097 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001098 locations->SetInAt(0, Location::RequiresRegister());
1099 locations->SetInAt(1, Location::RequiresRegister());
1100 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001101}
1102
1103void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1104 Label greater, done;
1105 LocationSummary* locations = compare->GetLocations();
1106 switch (compare->InputAt(0)->GetType()) {
1107 case Primitive::kPrimLong: {
1108 Register output = locations->Out().AsArm().AsCoreRegister();
1109 ArmManagedRegister left = locations->InAt(0).AsArm();
1110 ArmManagedRegister right = locations->InAt(1).AsArm();
1111 Label less, greater, done;
1112 __ cmp(left.AsRegisterPairHigh(),
1113 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1114 __ b(&less, LT);
1115 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001116 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1117 // the status flags.
1118 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001119 __ cmp(left.AsRegisterPairLow(),
1120 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001121 __ b(&done, EQ);
1122 __ b(&less, CC);
1123
1124 __ Bind(&greater);
1125 __ LoadImmediate(output, 1);
1126 __ b(&done);
1127
1128 __ Bind(&less);
1129 __ LoadImmediate(output, -1);
1130
1131 __ Bind(&done);
1132 break;
1133 }
1134 default:
1135 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1136 }
1137}
1138
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001139void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001140 LocationSummary* locations =
1141 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001142 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1143 locations->SetInAt(i, Location::Any());
1144 }
1145 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001146}
1147
1148void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001149 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001150}
1151
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001152void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001153 LocationSummary* locations =
1154 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001155 locations->SetInAt(0, Location::RequiresRegister());
1156 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001157 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001158 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001159 locations->AddTemp(Location::RequiresRegister());
1160 locations->AddTemp(Location::RequiresRegister());
1161 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001162}
1163
1164void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1165 LocationSummary* locations = instruction->GetLocations();
1166 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1167 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001168 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001169
1170 switch (field_type) {
1171 case Primitive::kPrimBoolean:
1172 case Primitive::kPrimByte: {
1173 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1174 __ StoreToOffset(kStoreByte, value, obj, offset);
1175 break;
1176 }
1177
1178 case Primitive::kPrimShort:
1179 case Primitive::kPrimChar: {
1180 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1181 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1182 break;
1183 }
1184
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001185 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001186 case Primitive::kPrimNot: {
1187 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1188 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001189 if (field_type == Primitive::kPrimNot) {
1190 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1191 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1192 codegen_->MarkGCCard(temp, card, obj, value);
1193 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001194 break;
1195 }
1196
1197 case Primitive::kPrimLong: {
1198 ArmManagedRegister value = locations->InAt(1).AsArm();
1199 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1200 break;
1201 }
1202
1203 case Primitive::kPrimFloat:
1204 case Primitive::kPrimDouble:
1205 LOG(FATAL) << "Unimplemented register type " << field_type;
1206
1207 case Primitive::kPrimVoid:
1208 LOG(FATAL) << "Unreachable type " << field_type;
1209 }
1210}
1211
1212void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001213 LocationSummary* locations =
1214 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001215 locations->SetInAt(0, Location::RequiresRegister());
1216 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001217}
1218
1219void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1220 LocationSummary* locations = instruction->GetLocations();
1221 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1222 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1223
1224 switch (instruction->GetType()) {
1225 case Primitive::kPrimBoolean: {
1226 Register out = locations->Out().AsArm().AsCoreRegister();
1227 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1228 break;
1229 }
1230
1231 case Primitive::kPrimByte: {
1232 Register out = locations->Out().AsArm().AsCoreRegister();
1233 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1234 break;
1235 }
1236
1237 case Primitive::kPrimShort: {
1238 Register out = locations->Out().AsArm().AsCoreRegister();
1239 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1240 break;
1241 }
1242
1243 case Primitive::kPrimChar: {
1244 Register out = locations->Out().AsArm().AsCoreRegister();
1245 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1246 break;
1247 }
1248
1249 case Primitive::kPrimInt:
1250 case Primitive::kPrimNot: {
1251 Register out = locations->Out().AsArm().AsCoreRegister();
1252 __ LoadFromOffset(kLoadWord, out, obj, offset);
1253 break;
1254 }
1255
1256 case Primitive::kPrimLong: {
1257 // TODO: support volatile.
1258 ArmManagedRegister out = locations->Out().AsArm();
1259 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1260 break;
1261 }
1262
1263 case Primitive::kPrimFloat:
1264 case Primitive::kPrimDouble:
1265 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1266
1267 case Primitive::kPrimVoid:
1268 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1269 }
1270}
1271
1272void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001273 LocationSummary* locations =
1274 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001275 locations->SetInAt(0, Location::RequiresRegister());
1276 // TODO: Have a normalization phase that makes this instruction never used.
1277 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001278}
1279
1280void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001281 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001282 codegen_->AddSlowPath(slow_path);
1283
1284 LocationSummary* locations = instruction->GetLocations();
1285 Location obj = locations->InAt(0);
1286 DCHECK(obj.Equals(locations->Out()));
1287
1288 if (obj.IsRegister()) {
1289 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1290 }
1291 __ b(slow_path->GetEntryLabel(), EQ);
1292}
1293
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001294void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001295 LocationSummary* locations =
1296 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001297 locations->SetInAt(0, Location::RequiresRegister());
1298 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1299 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001300}
1301
1302void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1303 LocationSummary* locations = instruction->GetLocations();
1304 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1305 Location index = locations->InAt(1);
1306
1307 switch (instruction->GetType()) {
1308 case Primitive::kPrimBoolean: {
1309 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1310 Register out = locations->Out().AsArm().AsCoreRegister();
1311 if (index.IsConstant()) {
1312 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1313 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1314 } else {
1315 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1316 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1317 }
1318 break;
1319 }
1320
1321 case Primitive::kPrimByte: {
1322 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1323 Register out = locations->Out().AsArm().AsCoreRegister();
1324 if (index.IsConstant()) {
1325 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1326 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1327 } else {
1328 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1329 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1330 }
1331 break;
1332 }
1333
1334 case Primitive::kPrimShort: {
1335 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1336 Register out = locations->Out().AsArm().AsCoreRegister();
1337 if (index.IsConstant()) {
1338 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1339 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1340 } else {
1341 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1342 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1343 }
1344 break;
1345 }
1346
1347 case Primitive::kPrimChar: {
1348 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1349 Register out = locations->Out().AsArm().AsCoreRegister();
1350 if (index.IsConstant()) {
1351 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1352 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1353 } else {
1354 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1355 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1356 }
1357 break;
1358 }
1359
1360 case Primitive::kPrimInt:
1361 case Primitive::kPrimNot: {
1362 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1363 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1364 Register out = locations->Out().AsArm().AsCoreRegister();
1365 if (index.IsConstant()) {
1366 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1367 __ LoadFromOffset(kLoadWord, out, obj, offset);
1368 } else {
1369 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1370 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1371 }
1372 break;
1373 }
1374
1375 case Primitive::kPrimLong: {
1376 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1377 ArmManagedRegister out = locations->Out().AsArm();
1378 if (index.IsConstant()) {
1379 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1380 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1381 } else {
1382 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1383 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1384 }
1385 break;
1386 }
1387
1388 case Primitive::kPrimFloat:
1389 case Primitive::kPrimDouble:
1390 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1391
1392 case Primitive::kPrimVoid:
1393 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1394 }
1395}
1396
1397void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001398 Primitive::Type value_type = instruction->GetComponentType();
1399 bool is_object = value_type == Primitive::kPrimNot;
1400 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1401 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1402 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001403 InvokeRuntimeCallingConvention calling_convention;
1404 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1405 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1406 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001407 } else {
1408 locations->SetInAt(0, Location::RequiresRegister());
1409 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1410 locations->SetInAt(2, Location::RequiresRegister());
1411 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001412}
1413
1414void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1415 LocationSummary* locations = instruction->GetLocations();
1416 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1417 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001418 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001419
1420 switch (value_type) {
1421 case Primitive::kPrimBoolean:
1422 case Primitive::kPrimByte: {
1423 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1424 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1425 if (index.IsConstant()) {
1426 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1427 __ StoreToOffset(kStoreByte, value, obj, offset);
1428 } else {
1429 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1430 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1431 }
1432 break;
1433 }
1434
1435 case Primitive::kPrimShort:
1436 case Primitive::kPrimChar: {
1437 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1438 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1439 if (index.IsConstant()) {
1440 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1441 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1442 } else {
1443 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1444 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1445 }
1446 break;
1447 }
1448
1449 case Primitive::kPrimInt: {
1450 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1451 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1452 if (index.IsConstant()) {
1453 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1454 __ StoreToOffset(kStoreWord, value, obj, offset);
1455 } else {
1456 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1457 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1458 }
1459 break;
1460 }
1461
1462 case Primitive::kPrimNot: {
1463 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1464 __ ldr(LR, Address(TR, offset));
1465 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001466 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001467 DCHECK(!codegen_->IsLeafMethod());
1468 break;
1469 }
1470
1471 case Primitive::kPrimLong: {
1472 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1473 ArmManagedRegister value = locations->InAt(2).AsArm();
1474 if (index.IsConstant()) {
1475 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1476 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1477 } else {
1478 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1479 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1480 }
1481 break;
1482 }
1483
1484 case Primitive::kPrimFloat:
1485 case Primitive::kPrimDouble:
1486 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1487
1488 case Primitive::kPrimVoid:
1489 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1490 }
1491}
1492
1493void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001494 LocationSummary* locations =
1495 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001496 locations->SetInAt(0, Location::RequiresRegister());
1497 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001498}
1499
1500void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1501 LocationSummary* locations = instruction->GetLocations();
1502 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1503 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1504 Register out = locations->Out().AsArm().AsCoreRegister();
1505 __ LoadFromOffset(kLoadWord, out, obj, offset);
1506}
1507
1508void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001509 LocationSummary* locations =
1510 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001511 locations->SetInAt(0, Location::RequiresRegister());
1512 locations->SetInAt(1, Location::RequiresRegister());
1513 // TODO: Have a normalization phase that makes this instruction never used.
1514 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001515}
1516
1517void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1518 LocationSummary* locations = instruction->GetLocations();
1519 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001520 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001521 codegen_->AddSlowPath(slow_path);
1522
1523 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1524 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1525
1526 __ cmp(index, ShifterOperand(length));
1527 __ b(slow_path->GetEntryLabel(), CS);
1528}
1529
1530void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1531 Label is_null;
1532 __ CompareAndBranchIfZero(value, &is_null);
1533 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1534 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1535 __ strb(card, Address(card, temp));
1536 __ Bind(&is_null);
1537}
1538
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001539void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1540 temp->SetLocations(nullptr);
1541}
1542
1543void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1544 // Nothing to do, this is driven by the code generator.
1545}
1546
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001547void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001548 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001549}
1550
1551void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001552 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1553}
1554
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001555void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1556 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1557}
1558
1559void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1560 SuspendCheckSlowPathARM* slow_path =
1561 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction);
1562 codegen_->AddSlowPath(slow_path);
1563
1564 __ AddConstant(R4, R4, -1);
1565 __ cmp(R4, ShifterOperand(0));
1566 __ b(slow_path->GetEntryLabel(), LE);
1567 __ Bind(slow_path->GetReturnLabel());
1568}
1569
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001570ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1571 return codegen_->GetAssembler();
1572}
1573
1574void ParallelMoveResolverARM::EmitMove(size_t index) {
1575 MoveOperands* move = moves_.Get(index);
1576 Location source = move->GetSource();
1577 Location destination = move->GetDestination();
1578
1579 if (source.IsRegister()) {
1580 if (destination.IsRegister()) {
1581 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1582 } else {
1583 DCHECK(destination.IsStackSlot());
1584 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1585 SP, destination.GetStackIndex());
1586 }
1587 } else if (source.IsStackSlot()) {
1588 if (destination.IsRegister()) {
1589 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1590 SP, source.GetStackIndex());
1591 } else {
1592 DCHECK(destination.IsStackSlot());
1593 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1594 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1595 }
1596 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001597 DCHECK(source.IsConstant());
1598 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1599 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1600 if (destination.IsRegister()) {
1601 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1602 } else {
1603 DCHECK(destination.IsStackSlot());
1604 __ LoadImmediate(IP, value);
1605 __ str(IP, Address(SP, destination.GetStackIndex()));
1606 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001607 }
1608}
1609
1610void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1611 __ Mov(IP, reg);
1612 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1613 __ StoreToOffset(kStoreWord, IP, SP, mem);
1614}
1615
1616void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1617 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1618 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1619 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1620 SP, mem1 + stack_offset);
1621 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1622 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1623 SP, mem2 + stack_offset);
1624 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1625}
1626
1627void ParallelMoveResolverARM::EmitSwap(size_t index) {
1628 MoveOperands* move = moves_.Get(index);
1629 Location source = move->GetSource();
1630 Location destination = move->GetDestination();
1631
1632 if (source.IsRegister() && destination.IsRegister()) {
1633 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1634 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1635 __ Mov(IP, source.AsArm().AsCoreRegister());
1636 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1637 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1638 } else if (source.IsRegister() && destination.IsStackSlot()) {
1639 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1640 } else if (source.IsStackSlot() && destination.IsRegister()) {
1641 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1642 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1643 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1644 } else {
1645 LOG(FATAL) << "Unimplemented";
1646 }
1647}
1648
1649void ParallelMoveResolverARM::SpillScratch(int reg) {
1650 __ Push(static_cast<Register>(reg));
1651}
1652
1653void ParallelMoveResolverARM::RestoreScratch(int reg) {
1654 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001655}
1656
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001657} // namespace arm
1658} // namespace art