blob: 1876cb9ca4fbd60b226af345eb358c16239c68ba [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:
Nicolas Geoffray3c049742014-09-24 18:10:46 +010096 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
97 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000098
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 Geoffray3c049742014-09-24 18:10:46 +0100107 if (successor_ == nullptr) {
108 __ b(GetReturnLabel());
109 } else {
110 __ b(codegen->GetLabelOf(successor_));
111 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000112 }
113
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100114 Label* GetReturnLabel() {
115 DCHECK(successor_ == nullptr);
116 return &return_label_;
117 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118
119 private:
120 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 // If not null, the block to branch to after the suspend check.
122 HBasicBlock* const successor_;
123
124 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125 Label return_label_;
126
127 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
128};
129
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100130class BoundsCheckSlowPathARM : public SlowPathCode {
131 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100132 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
133 Location index_location,
134 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100135 : instruction_(instruction),
136 index_location_(index_location),
137 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138
139 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
140 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
141 __ Bind(GetEntryLabel());
142 InvokeRuntimeCallingConvention calling_convention;
143 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
144 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
145 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
146 __ ldr(LR, Address(TR, offset));
147 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100148 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100149 }
150
151 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100153 const Location index_location_;
154 const Location length_location_;
155
156 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
157};
158
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100159#undef __
160#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700161
162inline Condition ARMCondition(IfCondition cond) {
163 switch (cond) {
164 case kCondEQ: return EQ;
165 case kCondNE: return NE;
166 case kCondLT: return LT;
167 case kCondLE: return LE;
168 case kCondGT: return GT;
169 case kCondGE: return GE;
170 default:
171 LOG(FATAL) << "Unknown if condition";
172 }
173 return EQ; // Unreachable.
174}
175
176inline Condition ARMOppositeCondition(IfCondition cond) {
177 switch (cond) {
178 case kCondEQ: return NE;
179 case kCondNE: return EQ;
180 case kCondLT: return GE;
181 case kCondLE: return GT;
182 case kCondGT: return LE;
183 case kCondGE: return LT;
184 default:
185 LOG(FATAL) << "Unknown if condition";
186 }
187 return EQ; // Unreachable.
188}
189
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100190void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
191 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
192}
193
194void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
195 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
196}
197
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100198void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
199 __ str(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
200}
201
202void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
203 __ ldr(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
204}
205
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100206CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
207 : CodeGenerator(graph, kNumberOfRegIds),
208 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100209 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100210 move_resolver_(graph->GetArena(), this),
211 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100212
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100213size_t CodeGeneratorARM::FrameEntrySpillSize() const {
214 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
215}
216
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100217static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
218 return blocked_registers + kNumberOfAllocIds;
219}
220
221ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
222 bool* blocked_registers) const {
223 switch (type) {
224 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100225 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
226 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100227 ArmManagedRegister pair =
228 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
229 blocked_registers[pair.AsRegisterPairLow()] = true;
230 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100231 // Block all other register pairs that share a register with `pair`.
232 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
233 ArmManagedRegister current =
234 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
235 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
236 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
237 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
238 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
239 blocked_register_pairs[i] = true;
240 }
241 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100242 return pair;
243 }
244
245 case Primitive::kPrimByte:
246 case Primitive::kPrimBoolean:
247 case Primitive::kPrimChar:
248 case Primitive::kPrimShort:
249 case Primitive::kPrimInt:
250 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100251 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
252 // Block all register pairs that contain `reg`.
253 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
254 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
255 ArmManagedRegister current =
256 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
257 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
258 blocked_register_pairs[i] = true;
259 }
260 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100261 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
262 }
263
264 case Primitive::kPrimFloat:
265 case Primitive::kPrimDouble:
266 LOG(FATAL) << "Unimplemented register type " << type;
267
268 case Primitive::kPrimVoid:
269 LOG(FATAL) << "Unreachable type " << type;
270 }
271
272 return ManagedRegister::NoRegister();
273}
274
275void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
276 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
277
278 // Don't allocate the dalvik style register pair passing.
279 blocked_register_pairs[R1_R2] = true;
280
281 // Stack register, LR and PC are always reserved.
282 blocked_registers[SP] = true;
283 blocked_registers[LR] = true;
284 blocked_registers[PC] = true;
285
286 // Reserve R4 for suspend check.
287 blocked_registers[R4] = true;
288 blocked_register_pairs[R4_R5] = true;
289
290 // Reserve thread register.
291 blocked_registers[TR] = true;
292
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100293 // Reserve temp register.
294 blocked_registers[IP] = true;
295
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100296 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100297 // We always save and restore R6 and R7 to make sure we can use three
298 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100299 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100300 blocked_registers[R8] = true;
301 blocked_registers[R10] = true;
302 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100303}
304
305size_t CodeGeneratorARM::GetNumberOfRegisters() const {
306 return kNumberOfRegIds;
307}
308
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100309InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
310 : HGraphVisitor(graph),
311 assembler_(codegen->GetAssembler()),
312 codegen_(codegen) {}
313
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000314void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700315 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100316 if (!skip_overflow_check) {
317 if (kExplicitStackOverflowCheck) {
318 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
319 AddSlowPath(slow_path);
320
321 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
322 __ cmp(SP, ShifterOperand(IP));
323 __ b(slow_path->GetEntryLabel(), CC);
324 } else {
325 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
326 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100327 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100328 }
329 }
330
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100331 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
332 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000333
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100334 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100335 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000336 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000337}
338
339void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100340 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100341 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000342}
343
344void CodeGeneratorARM::Bind(Label* label) {
345 __ Bind(label);
346}
347
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100348Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
349 switch (load->GetType()) {
350 case Primitive::kPrimLong:
351 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
352 break;
353
354 case Primitive::kPrimInt:
355 case Primitive::kPrimNot:
356 return Location::StackSlot(GetStackSlot(load->GetLocal()));
357
358 case Primitive::kPrimFloat:
359 case Primitive::kPrimDouble:
360 LOG(FATAL) << "Unimplemented type " << load->GetType();
361
362 case Primitive::kPrimBoolean:
363 case Primitive::kPrimByte:
364 case Primitive::kPrimChar:
365 case Primitive::kPrimShort:
366 case Primitive::kPrimVoid:
367 LOG(FATAL) << "Unexpected type " << load->GetType();
368 }
369
370 LOG(FATAL) << "Unreachable";
371 return Location();
372}
373
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100374Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
375 switch (type) {
376 case Primitive::kPrimBoolean:
377 case Primitive::kPrimByte:
378 case Primitive::kPrimChar:
379 case Primitive::kPrimShort:
380 case Primitive::kPrimInt:
381 case Primitive::kPrimNot: {
382 uint32_t index = gp_index_++;
383 if (index < calling_convention.GetNumberOfRegisters()) {
384 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
385 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100386 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100387 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100388 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100389
390 case Primitive::kPrimLong: {
391 uint32_t index = gp_index_;
392 gp_index_ += 2;
393 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
394 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
395 calling_convention.GetRegisterPairAt(index)));
396 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
397 return Location::QuickParameter(index);
398 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100399 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100400 }
401 }
402
403 case Primitive::kPrimDouble:
404 case Primitive::kPrimFloat:
405 LOG(FATAL) << "Unimplemented parameter type " << type;
406 break;
407
408 case Primitive::kPrimVoid:
409 LOG(FATAL) << "Unexpected parameter type " << type;
410 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100411 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100412 return Location();
413}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100414
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100415void CodeGeneratorARM::Move32(Location destination, Location source) {
416 if (source.Equals(destination)) {
417 return;
418 }
419 if (destination.IsRegister()) {
420 if (source.IsRegister()) {
421 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
422 } else {
423 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
424 }
425 } else {
426 DCHECK(destination.IsStackSlot());
427 if (source.IsRegister()) {
428 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
429 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100430 __ ldr(IP, Address(SP, source.GetStackIndex()));
431 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100432 }
433 }
434}
435
436void CodeGeneratorARM::Move64(Location destination, Location source) {
437 if (source.Equals(destination)) {
438 return;
439 }
440 if (destination.IsRegister()) {
441 if (source.IsRegister()) {
442 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
443 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
444 } else if (source.IsQuickParameter()) {
445 uint32_t argument_index = source.GetQuickParameterIndex();
446 InvokeDexCallingConvention calling_convention;
447 __ Mov(destination.AsArm().AsRegisterPairLow(),
448 calling_convention.GetRegisterAt(argument_index));
449 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100450 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100451 } else {
452 DCHECK(source.IsDoubleStackSlot());
453 if (destination.AsArm().AsRegisterPair() == R1_R2) {
454 __ ldr(R1, Address(SP, source.GetStackIndex()));
455 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
456 } else {
457 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
458 SP, source.GetStackIndex());
459 }
460 }
461 } else if (destination.IsQuickParameter()) {
462 InvokeDexCallingConvention calling_convention;
463 uint32_t argument_index = destination.GetQuickParameterIndex();
464 if (source.IsRegister()) {
465 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
466 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100467 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100468 } else {
469 DCHECK(source.IsDoubleStackSlot());
470 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100471 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
472 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100473 }
474 } else {
475 DCHECK(destination.IsDoubleStackSlot());
476 if (source.IsRegister()) {
477 if (source.AsArm().AsRegisterPair() == R1_R2) {
478 __ str(R1, Address(SP, destination.GetStackIndex()));
479 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
480 } else {
481 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
482 SP, destination.GetStackIndex());
483 }
484 } else if (source.IsQuickParameter()) {
485 InvokeDexCallingConvention calling_convention;
486 uint32_t argument_index = source.GetQuickParameterIndex();
487 __ str(calling_convention.GetRegisterAt(argument_index),
488 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100489 __ ldr(R0,
490 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
491 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100492 } else {
493 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100494 __ ldr(IP, Address(SP, source.GetStackIndex()));
495 __ str(IP, Address(SP, destination.GetStackIndex()));
496 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
497 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100498 }
499 }
500}
501
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100502void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100503 LocationSummary* locations = instruction->GetLocations();
504 if (locations != nullptr && locations->Out().Equals(location)) {
505 return;
506 }
507
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100508 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100509 int32_t value = instruction->AsIntConstant()->GetValue();
510 if (location.IsRegister()) {
511 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
512 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100513 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100514 __ LoadImmediate(IP, value);
515 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100516 }
517 } else if (instruction->AsLongConstant() != nullptr) {
518 int64_t value = instruction->AsLongConstant()->GetValue();
519 if (location.IsRegister()) {
520 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
521 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
522 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100523 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100524 __ LoadImmediate(IP, Low32Bits(value));
525 __ str(IP, Address(SP, location.GetStackIndex()));
526 __ LoadImmediate(IP, High32Bits(value));
527 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100528 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100529 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100530 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
531 switch (instruction->GetType()) {
532 case Primitive::kPrimBoolean:
533 case Primitive::kPrimByte:
534 case Primitive::kPrimChar:
535 case Primitive::kPrimShort:
536 case Primitive::kPrimInt:
537 case Primitive::kPrimNot:
538 Move32(location, Location::StackSlot(stack_slot));
539 break;
540
541 case Primitive::kPrimLong:
542 Move64(location, Location::DoubleStackSlot(stack_slot));
543 break;
544
545 default:
546 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
547 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000548 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100549 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100550 switch (instruction->GetType()) {
551 case Primitive::kPrimBoolean:
552 case Primitive::kPrimByte:
553 case Primitive::kPrimChar:
554 case Primitive::kPrimShort:
555 case Primitive::kPrimNot:
556 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100557 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100558 break;
559
560 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100561 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100562 break;
563
564 default:
565 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
566 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000567 }
568}
569
570void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000571 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000572}
573
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000574void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000575 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100576 DCHECK(!successor->IsExitBlock());
577
578 HBasicBlock* block = got->GetBlock();
579 HInstruction* previous = got->GetPrevious();
580
581 HLoopInformation* info = block->GetLoopInformation();
582 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
583 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
584 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
585 return;
586 }
587
588 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
589 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
590 }
591 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000592 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000593 }
594}
595
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000596void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000597 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000598}
599
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000600void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000601 if (kIsDebugBuild) {
602 __ Comment("Unreachable");
603 __ bkpt(0);
604 }
605}
606
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000607void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100608 LocationSummary* locations =
609 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100610 HInstruction* cond = if_instr->InputAt(0);
611 DCHECK(cond->IsCondition());
612 HCondition* condition = cond->AsCondition();
613 if (condition->NeedsMaterialization()) {
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100614 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100615 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000616}
617
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000618void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700619 HInstruction* cond = if_instr->InputAt(0);
620 DCHECK(cond->IsCondition());
621 HCondition* condition = cond->AsCondition();
622 if (condition->NeedsMaterialization()) {
623 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100624 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700625 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
626 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100627 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700628 } else {
629 // Condition has not been materialized, use its inputs as the comparison and its
630 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100631 LocationSummary* locations = condition->GetLocations();
632 if (locations->InAt(1).IsRegister()) {
633 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
634 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
635 } else {
636 DCHECK(locations->InAt(1).IsConstant());
637 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
638 ShifterOperand operand;
639 if (ShifterOperand::CanHoldArm(value, &operand)) {
640 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
641 } else {
642 Register temp = IP;
643 __ LoadImmediate(temp, value);
644 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
645 }
646 }
Dave Allison20dfc792014-06-16 20:44:29 -0700647 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
648 ARMCondition(condition->GetCondition()));
649 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100650
Dave Allison20dfc792014-06-16 20:44:29 -0700651 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
652 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000653 }
654}
655
Dave Allison20dfc792014-06-16 20:44:29 -0700656
657void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100658 LocationSummary* locations =
659 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100660 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100661 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100662 if (comp->NeedsMaterialization()) {
663 locations->SetOut(Location::RequiresRegister());
664 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000665}
666
Dave Allison20dfc792014-06-16 20:44:29 -0700667void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100668 if (!comp->NeedsMaterialization()) return;
669
670 LocationSummary* locations = comp->GetLocations();
671 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700672 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
673 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100674 } else {
675 DCHECK(locations->InAt(1).IsConstant());
676 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
677 ShifterOperand operand;
678 if (ShifterOperand::CanHoldArm(value, &operand)) {
679 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
680 } else {
681 Register temp = IP;
682 __ LoadImmediate(temp, value);
683 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
684 }
Dave Allison20dfc792014-06-16 20:44:29 -0700685 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100686 __ it(ARMCondition(comp->GetCondition()), kItElse);
687 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
688 ARMCondition(comp->GetCondition()));
689 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
690 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700691}
692
693void LocationsBuilderARM::VisitEqual(HEqual* comp) {
694 VisitCondition(comp);
695}
696
697void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
698 VisitCondition(comp);
699}
700
701void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
702 VisitCondition(comp);
703}
704
705void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
706 VisitCondition(comp);
707}
708
709void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
710 VisitCondition(comp);
711}
712
713void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
714 VisitCondition(comp);
715}
716
717void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
718 VisitCondition(comp);
719}
720
721void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
722 VisitCondition(comp);
723}
724
725void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
726 VisitCondition(comp);
727}
728
729void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
730 VisitCondition(comp);
731}
732
733void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
734 VisitCondition(comp);
735}
736
737void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
738 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000739}
740
741void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000742 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000743}
744
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000745void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
746 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000747}
748
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000749void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100750 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000751}
752
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000753void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100754 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000755}
756
757void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100758 LocationSummary* locations =
759 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100760 switch (store->InputAt(1)->GetType()) {
761 case Primitive::kPrimBoolean:
762 case Primitive::kPrimByte:
763 case Primitive::kPrimChar:
764 case Primitive::kPrimShort:
765 case Primitive::kPrimInt:
766 case Primitive::kPrimNot:
767 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
768 break;
769
770 case Primitive::kPrimLong:
771 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
772 break;
773
774 default:
775 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
776 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000777}
778
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000779void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000780}
781
782void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100783 LocationSummary* locations =
784 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100785 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000786}
787
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000788void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000789}
790
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100791void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100792 LocationSummary* locations =
793 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100794 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100795}
796
797void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
798 // Will be generated at use site.
799}
800
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000801void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000802 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000803}
804
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000805void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
806 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000807}
808
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000809void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100810 LocationSummary* locations =
811 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100812 switch (ret->InputAt(0)->GetType()) {
813 case Primitive::kPrimBoolean:
814 case Primitive::kPrimByte:
815 case Primitive::kPrimChar:
816 case Primitive::kPrimShort:
817 case Primitive::kPrimInt:
818 case Primitive::kPrimNot:
819 locations->SetInAt(0, ArmCoreLocation(R0));
820 break;
821
822 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100823 locations->SetInAt(
824 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100825 break;
826
827 default:
828 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
829 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000830}
831
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000832void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 if (kIsDebugBuild) {
834 switch (ret->InputAt(0)->GetType()) {
835 case Primitive::kPrimBoolean:
836 case Primitive::kPrimByte:
837 case Primitive::kPrimChar:
838 case Primitive::kPrimShort:
839 case Primitive::kPrimInt:
840 case Primitive::kPrimNot:
841 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
842 break;
843
844 case Primitive::kPrimLong:
845 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
846 break;
847
848 default:
849 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
850 }
851 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000852 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000853}
854
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000855void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100856 HandleInvoke(invoke);
857}
858
859void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
860 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
861}
862
863void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
864 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
865 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
866 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
867 invoke->GetIndexInDexCache() * kArmWordSize;
868
869 // TODO: Implement all kinds of calls:
870 // 1) boot -> boot
871 // 2) app -> boot
872 // 3) app -> app
873 //
874 // Currently we implement the app -> app logic, which looks up in the resolve cache.
875
876 // temp = method;
877 LoadCurrentMethod(temp);
878 // temp = temp->dex_cache_resolved_methods_;
879 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
880 // temp = temp[index_in_cache]
881 __ ldr(temp, Address(temp, index_in_cache));
882 // LR = temp[offset_of_quick_compiled_code]
883 __ ldr(LR, Address(temp,
884 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
885 // LR()
886 __ blx(LR);
887
888 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
889 DCHECK(!codegen_->IsLeafMethod());
890}
891
892void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
893 HandleInvoke(invoke);
894}
895
896void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100897 LocationSummary* locations =
898 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100899 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100900
901 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100902 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100903 HInstruction* input = invoke->InputAt(i);
904 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
905 }
906
907 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100908 case Primitive::kPrimBoolean:
909 case Primitive::kPrimByte:
910 case Primitive::kPrimChar:
911 case Primitive::kPrimShort:
912 case Primitive::kPrimInt:
913 case Primitive::kPrimNot:
914 locations->SetOut(ArmCoreLocation(R0));
915 break;
916
917 case Primitive::kPrimLong:
918 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
919 break;
920
921 case Primitive::kPrimVoid:
922 break;
923
924 case Primitive::kPrimDouble:
925 case Primitive::kPrimFloat:
926 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
927 break;
928 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000929}
930
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000931
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100932void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100933 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100934 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
935 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
936 LocationSummary* locations = invoke->GetLocations();
937 Location receiver = locations->InAt(0);
938 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
939 // temp = object->GetClass();
940 if (receiver.IsStackSlot()) {
941 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
942 __ ldr(temp, Address(temp, class_offset));
943 } else {
944 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
945 }
946 // temp = temp->GetMethodAt(method_offset);
947 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
948 __ ldr(temp, Address(temp, method_offset));
949 // LR = temp->GetEntryPoint();
950 __ ldr(LR, Address(temp, entry_point));
951 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000952 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100953 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100954 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000955}
956
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000957void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100958 LocationSummary* locations =
959 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000960 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100961 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100962 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100963 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100964 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100965 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100966 break;
967 }
968
969 case Primitive::kPrimBoolean:
970 case Primitive::kPrimByte:
971 case Primitive::kPrimChar:
972 case Primitive::kPrimShort:
973 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
974 break;
975
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000976 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100977 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000978 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000979}
980
981void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
982 LocationSummary* locations = add->GetLocations();
983 switch (add->GetResultType()) {
984 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100985 if (locations->InAt(1).IsRegister()) {
986 __ add(locations->Out().AsArm().AsCoreRegister(),
987 locations->InAt(0).AsArm().AsCoreRegister(),
988 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
989 } else {
990 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
991 locations->InAt(0).AsArm().AsCoreRegister(),
992 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
993 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000994 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100995
996 case Primitive::kPrimLong:
997 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
998 locations->InAt(0).AsArm().AsRegisterPairLow(),
999 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1000 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
1001 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1002 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1003 break;
1004
1005 case Primitive::kPrimBoolean:
1006 case Primitive::kPrimByte:
1007 case Primitive::kPrimChar:
1008 case Primitive::kPrimShort:
1009 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1010 break;
1011
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001012 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001013 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001014 }
1015}
1016
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001017void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001018 LocationSummary* locations =
1019 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001020 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001021 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001022 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001023 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001024 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001025 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001026 break;
1027 }
1028
1029 case Primitive::kPrimBoolean:
1030 case Primitive::kPrimByte:
1031 case Primitive::kPrimChar:
1032 case Primitive::kPrimShort:
1033 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1034 break;
1035
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001036 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001037 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001038 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001039}
1040
1041void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1042 LocationSummary* locations = sub->GetLocations();
1043 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001044 case Primitive::kPrimInt: {
1045 if (locations->InAt(1).IsRegister()) {
1046 __ sub(locations->Out().AsArm().AsCoreRegister(),
1047 locations->InAt(0).AsArm().AsCoreRegister(),
1048 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1049 } else {
1050 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1051 locations->InAt(0).AsArm().AsCoreRegister(),
1052 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1053 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001054 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001055 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001056
1057 case Primitive::kPrimLong:
1058 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1059 locations->InAt(0).AsArm().AsRegisterPairLow(),
1060 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1061 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1062 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1063 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1064 break;
1065
1066 case Primitive::kPrimBoolean:
1067 case Primitive::kPrimByte:
1068 case Primitive::kPrimChar:
1069 case Primitive::kPrimShort:
1070 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1071 break;
1072
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001073 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001074 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001075 }
1076}
1077
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001078void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001079 LocationSummary* locations =
1080 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001081 InvokeRuntimeCallingConvention calling_convention;
1082 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1083 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001084 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001085}
1086
1087void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1088 InvokeRuntimeCallingConvention calling_convention;
1089 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1090 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1091
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001092 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001093 __ ldr(LR, Address(TR, offset));
1094 __ blx(LR);
1095
Nicolas Geoffray39468442014-09-02 15:17:15 +01001096 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001097 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001098}
1099
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001100void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001101 LocationSummary* locations =
1102 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001103 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1104 if (location.IsStackSlot()) {
1105 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1106 } else if (location.IsDoubleStackSlot()) {
1107 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001108 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001109 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001110}
1111
1112void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001113 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001114}
1115
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001116void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001117 LocationSummary* locations =
1118 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001119 locations->SetInAt(0, Location::RequiresRegister());
1120 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001121}
1122
1123void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1124 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001125 __ eor(locations->Out().AsArm().AsCoreRegister(),
1126 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001127}
1128
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001129void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001130 LocationSummary* locations =
1131 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001132 locations->SetInAt(0, Location::RequiresRegister());
1133 locations->SetInAt(1, Location::RequiresRegister());
1134 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001135}
1136
1137void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1138 Label greater, done;
1139 LocationSummary* locations = compare->GetLocations();
1140 switch (compare->InputAt(0)->GetType()) {
1141 case Primitive::kPrimLong: {
1142 Register output = locations->Out().AsArm().AsCoreRegister();
1143 ArmManagedRegister left = locations->InAt(0).AsArm();
1144 ArmManagedRegister right = locations->InAt(1).AsArm();
1145 Label less, greater, done;
1146 __ cmp(left.AsRegisterPairHigh(),
1147 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1148 __ b(&less, LT);
1149 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001150 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1151 // the status flags.
1152 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001153 __ cmp(left.AsRegisterPairLow(),
1154 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001155 __ b(&done, EQ);
1156 __ b(&less, CC);
1157
1158 __ Bind(&greater);
1159 __ LoadImmediate(output, 1);
1160 __ b(&done);
1161
1162 __ Bind(&less);
1163 __ LoadImmediate(output, -1);
1164
1165 __ Bind(&done);
1166 break;
1167 }
1168 default:
1169 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1170 }
1171}
1172
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001173void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001174 LocationSummary* locations =
1175 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001176 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1177 locations->SetInAt(i, Location::Any());
1178 }
1179 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001180}
1181
1182void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001183 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001184}
1185
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001186void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001187 LocationSummary* locations =
1188 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001189 locations->SetInAt(0, Location::RequiresRegister());
1190 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001191 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001192 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001193 locations->AddTemp(Location::RequiresRegister());
1194 locations->AddTemp(Location::RequiresRegister());
1195 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001196}
1197
1198void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1199 LocationSummary* locations = instruction->GetLocations();
1200 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1201 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001202 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001203
1204 switch (field_type) {
1205 case Primitive::kPrimBoolean:
1206 case Primitive::kPrimByte: {
1207 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1208 __ StoreToOffset(kStoreByte, value, obj, offset);
1209 break;
1210 }
1211
1212 case Primitive::kPrimShort:
1213 case Primitive::kPrimChar: {
1214 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1215 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1216 break;
1217 }
1218
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001219 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001220 case Primitive::kPrimNot: {
1221 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1222 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001223 if (field_type == Primitive::kPrimNot) {
1224 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1225 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1226 codegen_->MarkGCCard(temp, card, obj, value);
1227 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001228 break;
1229 }
1230
1231 case Primitive::kPrimLong: {
1232 ArmManagedRegister value = locations->InAt(1).AsArm();
1233 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1234 break;
1235 }
1236
1237 case Primitive::kPrimFloat:
1238 case Primitive::kPrimDouble:
1239 LOG(FATAL) << "Unimplemented register type " << field_type;
1240
1241 case Primitive::kPrimVoid:
1242 LOG(FATAL) << "Unreachable type " << field_type;
1243 }
1244}
1245
1246void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001247 LocationSummary* locations =
1248 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001249 locations->SetInAt(0, Location::RequiresRegister());
1250 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001251}
1252
1253void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1254 LocationSummary* locations = instruction->GetLocations();
1255 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1256 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1257
1258 switch (instruction->GetType()) {
1259 case Primitive::kPrimBoolean: {
1260 Register out = locations->Out().AsArm().AsCoreRegister();
1261 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1262 break;
1263 }
1264
1265 case Primitive::kPrimByte: {
1266 Register out = locations->Out().AsArm().AsCoreRegister();
1267 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1268 break;
1269 }
1270
1271 case Primitive::kPrimShort: {
1272 Register out = locations->Out().AsArm().AsCoreRegister();
1273 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1274 break;
1275 }
1276
1277 case Primitive::kPrimChar: {
1278 Register out = locations->Out().AsArm().AsCoreRegister();
1279 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1280 break;
1281 }
1282
1283 case Primitive::kPrimInt:
1284 case Primitive::kPrimNot: {
1285 Register out = locations->Out().AsArm().AsCoreRegister();
1286 __ LoadFromOffset(kLoadWord, out, obj, offset);
1287 break;
1288 }
1289
1290 case Primitive::kPrimLong: {
1291 // TODO: support volatile.
1292 ArmManagedRegister out = locations->Out().AsArm();
1293 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1294 break;
1295 }
1296
1297 case Primitive::kPrimFloat:
1298 case Primitive::kPrimDouble:
1299 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1300
1301 case Primitive::kPrimVoid:
1302 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1303 }
1304}
1305
1306void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001307 LocationSummary* locations =
1308 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001309 locations->SetInAt(0, Location::RequiresRegister());
1310 // TODO: Have a normalization phase that makes this instruction never used.
1311 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001312}
1313
1314void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001315 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001316 codegen_->AddSlowPath(slow_path);
1317
1318 LocationSummary* locations = instruction->GetLocations();
1319 Location obj = locations->InAt(0);
1320 DCHECK(obj.Equals(locations->Out()));
1321
1322 if (obj.IsRegister()) {
1323 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1324 }
1325 __ b(slow_path->GetEntryLabel(), EQ);
1326}
1327
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001328void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001329 LocationSummary* locations =
1330 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001331 locations->SetInAt(0, Location::RequiresRegister());
1332 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1333 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001334}
1335
1336void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1337 LocationSummary* locations = instruction->GetLocations();
1338 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1339 Location index = locations->InAt(1);
1340
1341 switch (instruction->GetType()) {
1342 case Primitive::kPrimBoolean: {
1343 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1344 Register out = locations->Out().AsArm().AsCoreRegister();
1345 if (index.IsConstant()) {
1346 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1347 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1348 } else {
1349 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1350 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1351 }
1352 break;
1353 }
1354
1355 case Primitive::kPrimByte: {
1356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1357 Register out = locations->Out().AsArm().AsCoreRegister();
1358 if (index.IsConstant()) {
1359 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1360 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1361 } else {
1362 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1363 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1364 }
1365 break;
1366 }
1367
1368 case Primitive::kPrimShort: {
1369 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1370 Register out = locations->Out().AsArm().AsCoreRegister();
1371 if (index.IsConstant()) {
1372 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1373 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1374 } else {
1375 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1376 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1377 }
1378 break;
1379 }
1380
1381 case Primitive::kPrimChar: {
1382 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1383 Register out = locations->Out().AsArm().AsCoreRegister();
1384 if (index.IsConstant()) {
1385 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1386 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1387 } else {
1388 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1389 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1390 }
1391 break;
1392 }
1393
1394 case Primitive::kPrimInt:
1395 case Primitive::kPrimNot: {
1396 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1397 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1398 Register out = locations->Out().AsArm().AsCoreRegister();
1399 if (index.IsConstant()) {
1400 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1401 __ LoadFromOffset(kLoadWord, out, obj, offset);
1402 } else {
1403 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1404 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1405 }
1406 break;
1407 }
1408
1409 case Primitive::kPrimLong: {
1410 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1411 ArmManagedRegister out = locations->Out().AsArm();
1412 if (index.IsConstant()) {
1413 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1414 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1415 } else {
1416 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1417 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1418 }
1419 break;
1420 }
1421
1422 case Primitive::kPrimFloat:
1423 case Primitive::kPrimDouble:
1424 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1425
1426 case Primitive::kPrimVoid:
1427 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1428 }
1429}
1430
1431void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001432 Primitive::Type value_type = instruction->GetComponentType();
1433 bool is_object = value_type == Primitive::kPrimNot;
1434 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1435 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1436 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001437 InvokeRuntimeCallingConvention calling_convention;
1438 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1439 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1440 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001441 } else {
1442 locations->SetInAt(0, Location::RequiresRegister());
1443 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1444 locations->SetInAt(2, Location::RequiresRegister());
1445 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001446}
1447
1448void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1449 LocationSummary* locations = instruction->GetLocations();
1450 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1451 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001452 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001453
1454 switch (value_type) {
1455 case Primitive::kPrimBoolean:
1456 case Primitive::kPrimByte: {
1457 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1458 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1459 if (index.IsConstant()) {
1460 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1461 __ StoreToOffset(kStoreByte, value, obj, offset);
1462 } else {
1463 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1464 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1465 }
1466 break;
1467 }
1468
1469 case Primitive::kPrimShort:
1470 case Primitive::kPrimChar: {
1471 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1472 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1473 if (index.IsConstant()) {
1474 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1475 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1476 } else {
1477 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1478 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1479 }
1480 break;
1481 }
1482
1483 case Primitive::kPrimInt: {
1484 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1485 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1486 if (index.IsConstant()) {
1487 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1488 __ StoreToOffset(kStoreWord, value, obj, offset);
1489 } else {
1490 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1491 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1492 }
1493 break;
1494 }
1495
1496 case Primitive::kPrimNot: {
1497 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1498 __ ldr(LR, Address(TR, offset));
1499 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001500 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001501 DCHECK(!codegen_->IsLeafMethod());
1502 break;
1503 }
1504
1505 case Primitive::kPrimLong: {
1506 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1507 ArmManagedRegister value = locations->InAt(2).AsArm();
1508 if (index.IsConstant()) {
1509 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1510 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1511 } else {
1512 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1513 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1514 }
1515 break;
1516 }
1517
1518 case Primitive::kPrimFloat:
1519 case Primitive::kPrimDouble:
1520 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1521
1522 case Primitive::kPrimVoid:
1523 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1524 }
1525}
1526
1527void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001528 LocationSummary* locations =
1529 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001530 locations->SetInAt(0, Location::RequiresRegister());
1531 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001532}
1533
1534void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1535 LocationSummary* locations = instruction->GetLocations();
1536 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1537 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1538 Register out = locations->Out().AsArm().AsCoreRegister();
1539 __ LoadFromOffset(kLoadWord, out, obj, offset);
1540}
1541
1542void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001543 LocationSummary* locations =
1544 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001545 locations->SetInAt(0, Location::RequiresRegister());
1546 locations->SetInAt(1, Location::RequiresRegister());
1547 // TODO: Have a normalization phase that makes this instruction never used.
1548 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001549}
1550
1551void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1552 LocationSummary* locations = instruction->GetLocations();
1553 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001554 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001555 codegen_->AddSlowPath(slow_path);
1556
1557 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1558 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1559
1560 __ cmp(index, ShifterOperand(length));
1561 __ b(slow_path->GetEntryLabel(), CS);
1562}
1563
1564void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1565 Label is_null;
1566 __ CompareAndBranchIfZero(value, &is_null);
1567 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1568 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1569 __ strb(card, Address(card, temp));
1570 __ Bind(&is_null);
1571}
1572
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001573void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1574 temp->SetLocations(nullptr);
1575}
1576
1577void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1578 // Nothing to do, this is driven by the code generator.
1579}
1580
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001581void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001582 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001583}
1584
1585void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001586 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1587}
1588
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001589void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1590 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1591}
1592
1593void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001594 HBasicBlock* block = instruction->GetBlock();
1595 if (block->GetLoopInformation() != nullptr) {
1596 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1597 // The back edge will generate the suspend check.
1598 return;
1599 }
1600 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1601 // The goto will generate the suspend check.
1602 return;
1603 }
1604 GenerateSuspendCheck(instruction, nullptr);
1605}
1606
1607void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1608 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001609 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001610 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001611 codegen_->AddSlowPath(slow_path);
1612
1613 __ AddConstant(R4, R4, -1);
1614 __ cmp(R4, ShifterOperand(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001615 if (successor == nullptr) {
1616 __ b(slow_path->GetEntryLabel(), LE);
1617 __ Bind(slow_path->GetReturnLabel());
1618 } else {
1619 __ b(codegen_->GetLabelOf(successor), GT);
1620 __ b(slow_path->GetEntryLabel());
1621 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001622}
1623
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001624ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1625 return codegen_->GetAssembler();
1626}
1627
1628void ParallelMoveResolverARM::EmitMove(size_t index) {
1629 MoveOperands* move = moves_.Get(index);
1630 Location source = move->GetSource();
1631 Location destination = move->GetDestination();
1632
1633 if (source.IsRegister()) {
1634 if (destination.IsRegister()) {
1635 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1636 } else {
1637 DCHECK(destination.IsStackSlot());
1638 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1639 SP, destination.GetStackIndex());
1640 }
1641 } else if (source.IsStackSlot()) {
1642 if (destination.IsRegister()) {
1643 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1644 SP, source.GetStackIndex());
1645 } else {
1646 DCHECK(destination.IsStackSlot());
1647 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1648 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1649 }
1650 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001651 DCHECK(source.IsConstant());
1652 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1653 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1654 if (destination.IsRegister()) {
1655 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1656 } else {
1657 DCHECK(destination.IsStackSlot());
1658 __ LoadImmediate(IP, value);
1659 __ str(IP, Address(SP, destination.GetStackIndex()));
1660 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001661 }
1662}
1663
1664void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1665 __ Mov(IP, reg);
1666 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1667 __ StoreToOffset(kStoreWord, IP, SP, mem);
1668}
1669
1670void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1671 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1672 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1673 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1674 SP, mem1 + stack_offset);
1675 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1676 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1677 SP, mem2 + stack_offset);
1678 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1679}
1680
1681void ParallelMoveResolverARM::EmitSwap(size_t index) {
1682 MoveOperands* move = moves_.Get(index);
1683 Location source = move->GetSource();
1684 Location destination = move->GetDestination();
1685
1686 if (source.IsRegister() && destination.IsRegister()) {
1687 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1688 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1689 __ Mov(IP, source.AsArm().AsCoreRegister());
1690 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1691 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1692 } else if (source.IsRegister() && destination.IsStackSlot()) {
1693 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1694 } else if (source.IsStackSlot() && destination.IsRegister()) {
1695 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1696 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1697 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1698 } else {
1699 LOG(FATAL) << "Unimplemented";
1700 }
1701}
1702
1703void ParallelMoveResolverARM::SpillScratch(int reg) {
1704 __ Push(static_cast<Register>(reg));
1705}
1706
1707void ParallelMoveResolverARM::RestoreScratch(int reg) {
1708 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001709}
1710
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001711} // namespace arm
1712} // namespace art