blob: 9d875df1fe7f22f523babc0f5139c90416456011 [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 Geoffray9ae0daa2014-09-30 22:40:23 +0100614 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
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 Geoffray9ae0daa2014-09-30 22:40:23 +0100660 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
661 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
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 Geoffray9ae0daa2014-09-30 22:40:23 +0100963 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
964 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
965 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100966 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100967 break;
968 }
969
970 case Primitive::kPrimBoolean:
971 case Primitive::kPrimByte:
972 case Primitive::kPrimChar:
973 case Primitive::kPrimShort:
974 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
975 break;
976
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000977 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100978 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000979 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000980}
981
982void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
983 LocationSummary* locations = add->GetLocations();
984 switch (add->GetResultType()) {
985 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100986 if (locations->InAt(1).IsRegister()) {
987 __ add(locations->Out().AsArm().AsCoreRegister(),
988 locations->InAt(0).AsArm().AsCoreRegister(),
989 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
990 } else {
991 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
992 locations->InAt(0).AsArm().AsCoreRegister(),
993 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
994 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000995 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100996
997 case Primitive::kPrimLong:
998 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
999 locations->InAt(0).AsArm().AsRegisterPairLow(),
1000 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1001 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
1002 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1003 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1004 break;
1005
1006 case Primitive::kPrimBoolean:
1007 case Primitive::kPrimByte:
1008 case Primitive::kPrimChar:
1009 case Primitive::kPrimShort:
1010 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1011 break;
1012
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001013 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001014 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001015 }
1016}
1017
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001018void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001019 LocationSummary* locations =
1020 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001021 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001022 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001023 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001024 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1025 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1026 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001027 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001028 break;
1029 }
1030
1031 case Primitive::kPrimBoolean:
1032 case Primitive::kPrimByte:
1033 case Primitive::kPrimChar:
1034 case Primitive::kPrimShort:
1035 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1036 break;
1037
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001038 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001039 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001040 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001041}
1042
1043void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1044 LocationSummary* locations = sub->GetLocations();
1045 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001046 case Primitive::kPrimInt: {
1047 if (locations->InAt(1).IsRegister()) {
1048 __ sub(locations->Out().AsArm().AsCoreRegister(),
1049 locations->InAt(0).AsArm().AsCoreRegister(),
1050 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1051 } else {
1052 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1053 locations->InAt(0).AsArm().AsCoreRegister(),
1054 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1055 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001056 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001057 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001058
1059 case Primitive::kPrimLong:
1060 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1061 locations->InAt(0).AsArm().AsRegisterPairLow(),
1062 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1063 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1064 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1065 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1066 break;
1067
1068 case Primitive::kPrimBoolean:
1069 case Primitive::kPrimByte:
1070 case Primitive::kPrimChar:
1071 case Primitive::kPrimShort:
1072 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1073 break;
1074
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001075 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001076 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001077 }
1078}
1079
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001080void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001081 LocationSummary* locations =
1082 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001083 InvokeRuntimeCallingConvention calling_convention;
1084 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1085 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001086 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001087}
1088
1089void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1090 InvokeRuntimeCallingConvention calling_convention;
1091 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1092 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1093
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001094 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001095 __ ldr(LR, Address(TR, offset));
1096 __ blx(LR);
1097
Nicolas Geoffray39468442014-09-02 15:17:15 +01001098 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001099 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001100}
1101
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001102void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001103 LocationSummary* locations =
1104 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001105 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1106 if (location.IsStackSlot()) {
1107 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1108 } else if (location.IsDoubleStackSlot()) {
1109 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001110 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001111 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001112}
1113
1114void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001116}
1117
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001118void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001119 LocationSummary* locations =
1120 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001121 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001122 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001123}
1124
1125void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1126 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001127 __ eor(locations->Out().AsArm().AsCoreRegister(),
1128 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001129}
1130
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001131void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001132 LocationSummary* locations =
1133 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001134 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1135 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001136 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001137}
1138
1139void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1140 Label greater, done;
1141 LocationSummary* locations = compare->GetLocations();
1142 switch (compare->InputAt(0)->GetType()) {
1143 case Primitive::kPrimLong: {
1144 Register output = locations->Out().AsArm().AsCoreRegister();
1145 ArmManagedRegister left = locations->InAt(0).AsArm();
1146 ArmManagedRegister right = locations->InAt(1).AsArm();
1147 Label less, greater, done;
1148 __ cmp(left.AsRegisterPairHigh(),
1149 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1150 __ b(&less, LT);
1151 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001152 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1153 // the status flags.
1154 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001155 __ cmp(left.AsRegisterPairLow(),
1156 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001157 __ b(&done, EQ);
1158 __ b(&less, CC);
1159
1160 __ Bind(&greater);
1161 __ LoadImmediate(output, 1);
1162 __ b(&done);
1163
1164 __ Bind(&less);
1165 __ LoadImmediate(output, -1);
1166
1167 __ Bind(&done);
1168 break;
1169 }
1170 default:
1171 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1172 }
1173}
1174
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001175void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001176 LocationSummary* locations =
1177 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001178 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1179 locations->SetInAt(i, Location::Any());
1180 }
1181 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001182}
1183
1184void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001185 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001186}
1187
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001188void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001189 LocationSummary* locations =
1190 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001191 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1192 bool dies_at_entry = !is_object_type;
1193 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1194 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001195 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001196 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001197 locations->AddTemp(Location::RequiresRegister());
1198 locations->AddTemp(Location::RequiresRegister());
1199 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001200}
1201
1202void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1203 LocationSummary* locations = instruction->GetLocations();
1204 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1205 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001206 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001207
1208 switch (field_type) {
1209 case Primitive::kPrimBoolean:
1210 case Primitive::kPrimByte: {
1211 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1212 __ StoreToOffset(kStoreByte, value, obj, offset);
1213 break;
1214 }
1215
1216 case Primitive::kPrimShort:
1217 case Primitive::kPrimChar: {
1218 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1219 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1220 break;
1221 }
1222
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001223 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001224 case Primitive::kPrimNot: {
1225 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1226 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001227 if (field_type == Primitive::kPrimNot) {
1228 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1229 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1230 codegen_->MarkGCCard(temp, card, obj, value);
1231 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001232 break;
1233 }
1234
1235 case Primitive::kPrimLong: {
1236 ArmManagedRegister value = locations->InAt(1).AsArm();
1237 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1238 break;
1239 }
1240
1241 case Primitive::kPrimFloat:
1242 case Primitive::kPrimDouble:
1243 LOG(FATAL) << "Unimplemented register type " << field_type;
1244
1245 case Primitive::kPrimVoid:
1246 LOG(FATAL) << "Unreachable type " << field_type;
1247 }
1248}
1249
1250void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001251 LocationSummary* locations =
1252 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001253 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001254 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001255}
1256
1257void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1258 LocationSummary* locations = instruction->GetLocations();
1259 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1260 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1261
1262 switch (instruction->GetType()) {
1263 case Primitive::kPrimBoolean: {
1264 Register out = locations->Out().AsArm().AsCoreRegister();
1265 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1266 break;
1267 }
1268
1269 case Primitive::kPrimByte: {
1270 Register out = locations->Out().AsArm().AsCoreRegister();
1271 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1272 break;
1273 }
1274
1275 case Primitive::kPrimShort: {
1276 Register out = locations->Out().AsArm().AsCoreRegister();
1277 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1278 break;
1279 }
1280
1281 case Primitive::kPrimChar: {
1282 Register out = locations->Out().AsArm().AsCoreRegister();
1283 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1284 break;
1285 }
1286
1287 case Primitive::kPrimInt:
1288 case Primitive::kPrimNot: {
1289 Register out = locations->Out().AsArm().AsCoreRegister();
1290 __ LoadFromOffset(kLoadWord, out, obj, offset);
1291 break;
1292 }
1293
1294 case Primitive::kPrimLong: {
1295 // TODO: support volatile.
1296 ArmManagedRegister out = locations->Out().AsArm();
1297 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1298 break;
1299 }
1300
1301 case Primitive::kPrimFloat:
1302 case Primitive::kPrimDouble:
1303 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1304
1305 case Primitive::kPrimVoid:
1306 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1307 }
1308}
1309
1310void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001311 LocationSummary* locations =
1312 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001313 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001314 if (instruction->HasUses()) {
1315 locations->SetOut(Location::SameAsFirstInput());
1316 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001317}
1318
1319void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001320 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001321 codegen_->AddSlowPath(slow_path);
1322
1323 LocationSummary* locations = instruction->GetLocations();
1324 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001325
1326 if (obj.IsRegister()) {
1327 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001328 __ b(slow_path->GetEntryLabel(), EQ);
1329 } else {
1330 DCHECK(obj.IsConstant()) << obj;
1331 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1332 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001333 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001334}
1335
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001336void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001337 LocationSummary* locations =
1338 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001339 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1340 locations->SetInAt(
1341 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001342 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001343}
1344
1345void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1346 LocationSummary* locations = instruction->GetLocations();
1347 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1348 Location index = locations->InAt(1);
1349
1350 switch (instruction->GetType()) {
1351 case Primitive::kPrimBoolean: {
1352 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1353 Register out = locations->Out().AsArm().AsCoreRegister();
1354 if (index.IsConstant()) {
1355 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1356 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1357 } else {
1358 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1359 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1360 }
1361 break;
1362 }
1363
1364 case Primitive::kPrimByte: {
1365 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1366 Register out = locations->Out().AsArm().AsCoreRegister();
1367 if (index.IsConstant()) {
1368 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1369 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1370 } else {
1371 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1372 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1373 }
1374 break;
1375 }
1376
1377 case Primitive::kPrimShort: {
1378 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1379 Register out = locations->Out().AsArm().AsCoreRegister();
1380 if (index.IsConstant()) {
1381 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1382 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1383 } else {
1384 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1385 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1386 }
1387 break;
1388 }
1389
1390 case Primitive::kPrimChar: {
1391 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1392 Register out = locations->Out().AsArm().AsCoreRegister();
1393 if (index.IsConstant()) {
1394 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1395 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1396 } else {
1397 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1398 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1399 }
1400 break;
1401 }
1402
1403 case Primitive::kPrimInt:
1404 case Primitive::kPrimNot: {
1405 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1406 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1407 Register out = locations->Out().AsArm().AsCoreRegister();
1408 if (index.IsConstant()) {
1409 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1410 __ LoadFromOffset(kLoadWord, out, obj, offset);
1411 } else {
1412 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1413 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1414 }
1415 break;
1416 }
1417
1418 case Primitive::kPrimLong: {
1419 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1420 ArmManagedRegister out = locations->Out().AsArm();
1421 if (index.IsConstant()) {
1422 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1423 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1424 } else {
1425 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1426 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1427 }
1428 break;
1429 }
1430
1431 case Primitive::kPrimFloat:
1432 case Primitive::kPrimDouble:
1433 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1434
1435 case Primitive::kPrimVoid:
1436 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1437 }
1438}
1439
1440void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001441 Primitive::Type value_type = instruction->GetComponentType();
1442 bool is_object = value_type == Primitive::kPrimNot;
1443 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1444 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1445 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001446 InvokeRuntimeCallingConvention calling_convention;
1447 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1448 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1449 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001450 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001451 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1452 locations->SetInAt(
1453 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1454 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001455 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001456}
1457
1458void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1459 LocationSummary* locations = instruction->GetLocations();
1460 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1461 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001462 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001463
1464 switch (value_type) {
1465 case Primitive::kPrimBoolean:
1466 case Primitive::kPrimByte: {
1467 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1468 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1469 if (index.IsConstant()) {
1470 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1471 __ StoreToOffset(kStoreByte, value, obj, offset);
1472 } else {
1473 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1474 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1475 }
1476 break;
1477 }
1478
1479 case Primitive::kPrimShort:
1480 case Primitive::kPrimChar: {
1481 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1482 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1483 if (index.IsConstant()) {
1484 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1485 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1486 } else {
1487 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1488 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1489 }
1490 break;
1491 }
1492
1493 case Primitive::kPrimInt: {
1494 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1495 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1496 if (index.IsConstant()) {
1497 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1498 __ StoreToOffset(kStoreWord, value, obj, offset);
1499 } else {
1500 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1501 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1502 }
1503 break;
1504 }
1505
1506 case Primitive::kPrimNot: {
1507 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1508 __ ldr(LR, Address(TR, offset));
1509 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001510 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001511 DCHECK(!codegen_->IsLeafMethod());
1512 break;
1513 }
1514
1515 case Primitive::kPrimLong: {
1516 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1517 ArmManagedRegister value = locations->InAt(2).AsArm();
1518 if (index.IsConstant()) {
1519 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1520 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1521 } else {
1522 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1523 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1524 }
1525 break;
1526 }
1527
1528 case Primitive::kPrimFloat:
1529 case Primitive::kPrimDouble:
1530 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1531
1532 case Primitive::kPrimVoid:
1533 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1534 }
1535}
1536
1537void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001538 LocationSummary* locations =
1539 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001540 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001541 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001542}
1543
1544void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1545 LocationSummary* locations = instruction->GetLocations();
1546 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1547 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1548 Register out = locations->Out().AsArm().AsCoreRegister();
1549 __ LoadFromOffset(kLoadWord, out, obj, offset);
1550}
1551
1552void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001553 LocationSummary* locations =
1554 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001555 locations->SetInAt(0, Location::RequiresRegister());
1556 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001557 if (instruction->HasUses()) {
1558 locations->SetOut(Location::SameAsFirstInput());
1559 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001560}
1561
1562void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1563 LocationSummary* locations = instruction->GetLocations();
1564 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001565 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001566 codegen_->AddSlowPath(slow_path);
1567
1568 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1569 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1570
1571 __ cmp(index, ShifterOperand(length));
1572 __ b(slow_path->GetEntryLabel(), CS);
1573}
1574
1575void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1576 Label is_null;
1577 __ CompareAndBranchIfZero(value, &is_null);
1578 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1579 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1580 __ strb(card, Address(card, temp));
1581 __ Bind(&is_null);
1582}
1583
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001584void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1585 temp->SetLocations(nullptr);
1586}
1587
1588void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1589 // Nothing to do, this is driven by the code generator.
1590}
1591
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001592void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001593 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001594}
1595
1596void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001597 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1598}
1599
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001600void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1602}
1603
1604void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001605 HBasicBlock* block = instruction->GetBlock();
1606 if (block->GetLoopInformation() != nullptr) {
1607 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1608 // The back edge will generate the suspend check.
1609 return;
1610 }
1611 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1612 // The goto will generate the suspend check.
1613 return;
1614 }
1615 GenerateSuspendCheck(instruction, nullptr);
1616}
1617
1618void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1619 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001620 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001621 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001622 codegen_->AddSlowPath(slow_path);
1623
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001624 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001625 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001626 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001627 __ Bind(slow_path->GetReturnLabel());
1628 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001629 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001630 __ b(slow_path->GetEntryLabel());
1631 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001632}
1633
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001634ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1635 return codegen_->GetAssembler();
1636}
1637
1638void ParallelMoveResolverARM::EmitMove(size_t index) {
1639 MoveOperands* move = moves_.Get(index);
1640 Location source = move->GetSource();
1641 Location destination = move->GetDestination();
1642
1643 if (source.IsRegister()) {
1644 if (destination.IsRegister()) {
1645 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1646 } else {
1647 DCHECK(destination.IsStackSlot());
1648 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1649 SP, destination.GetStackIndex());
1650 }
1651 } else if (source.IsStackSlot()) {
1652 if (destination.IsRegister()) {
1653 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1654 SP, source.GetStackIndex());
1655 } else {
1656 DCHECK(destination.IsStackSlot());
1657 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1658 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1659 }
1660 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001661 DCHECK(source.IsConstant());
1662 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1663 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1664 if (destination.IsRegister()) {
1665 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1666 } else {
1667 DCHECK(destination.IsStackSlot());
1668 __ LoadImmediate(IP, value);
1669 __ str(IP, Address(SP, destination.GetStackIndex()));
1670 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001671 }
1672}
1673
1674void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1675 __ Mov(IP, reg);
1676 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1677 __ StoreToOffset(kStoreWord, IP, SP, mem);
1678}
1679
1680void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1681 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1682 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1683 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1684 SP, mem1 + stack_offset);
1685 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1686 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1687 SP, mem2 + stack_offset);
1688 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1689}
1690
1691void ParallelMoveResolverARM::EmitSwap(size_t index) {
1692 MoveOperands* move = moves_.Get(index);
1693 Location source = move->GetSource();
1694 Location destination = move->GetDestination();
1695
1696 if (source.IsRegister() && destination.IsRegister()) {
1697 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1698 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1699 __ Mov(IP, source.AsArm().AsCoreRegister());
1700 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1701 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1702 } else if (source.IsRegister() && destination.IsStackSlot()) {
1703 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1704 } else if (source.IsStackSlot() && destination.IsRegister()) {
1705 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1706 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1707 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1708 } else {
1709 LOG(FATAL) << "Unimplemented";
1710 }
1711}
1712
1713void ParallelMoveResolverARM::SpillScratch(int reg) {
1714 __ Push(static_cast<Register>(reg));
1715}
1716
1717void ParallelMoveResolverARM::RestoreScratch(int reg) {
1718 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001719}
1720
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001721} // namespace arm
1722} // namespace art