blob: 99030922a705ee40815724d5c077773b6a8cd258 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070019#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000021#include "mirror/array.h"
22#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070023#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010024#include "utils/assembler.h"
25#include "utils/arm/assembler_arm.h"
26#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010027#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000028
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010030
31arm::ArmManagedRegister Location::AsArm() const {
32 return reg().AsArm();
33}
34
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace arm {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037static constexpr bool kExplicitStackOverflowCheck = false;
38
39static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
40static constexpr int kCurrentMethodStackOffset = 0;
41
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042static Location ArmCoreLocation(Register reg) {
43 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
44}
45
46static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
47static constexpr size_t kRuntimeParameterCoreRegistersLength =
48 arraysize(kRuntimeParameterCoreRegisters);
49
50class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
51 public:
52 InvokeRuntimeCallingConvention()
53 : CallingConvention(kRuntimeParameterCoreRegisters,
54 kRuntimeParameterCoreRegistersLength) {}
55
56 private:
57 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
58};
59
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
61
62class NullCheckSlowPathARM : public SlowPathCode {
63 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010064 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
66 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
67 __ Bind(GetEntryLabel());
68 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
69 __ ldr(LR, Address(TR, offset));
70 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 }
73
74 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
77};
78
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010079class StackOverflowCheckSlowPathARM : public SlowPathCode {
80 public:
81 StackOverflowCheckSlowPathARM() {}
82
83 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
84 __ Bind(GetEntryLabel());
85 __ LoadFromOffset(kLoadWord, PC, TR,
86 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
87 }
88
89 private:
90 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
91};
92
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000093class SuspendCheckSlowPathARM : public SlowPathCode {
94 public:
95 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction)
96 : instruction_(instruction) {}
97
98 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
99 __ Bind(GetEntryLabel());
100 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
101 __ ldr(LR, Address(TR, offset));
102 __ blx(LR);
103 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
104 __ b(GetReturnLabel());
105 }
106
107 Label* GetReturnLabel() { return &return_label_; }
108
109 private:
110 HSuspendCheck* const instruction_;
111 Label return_label_;
112
113 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
114};
115
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100116class BoundsCheckSlowPathARM : public SlowPathCode {
117 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100118 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100119 Location index_location,
120 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100121 : instruction_(instruction),
122 index_location_(index_location),
123 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100124
125 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
126 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
127 __ Bind(GetEntryLabel());
128 InvokeRuntimeCallingConvention calling_convention;
129 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
130 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
131 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
132 __ ldr(LR, Address(TR, offset));
133 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100134 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100135 }
136
137 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100138 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100139 const Location index_location_;
140 const Location length_location_;
141
142 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
143};
144
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100145#undef __
146#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700147
148inline Condition ARMCondition(IfCondition cond) {
149 switch (cond) {
150 case kCondEQ: return EQ;
151 case kCondNE: return NE;
152 case kCondLT: return LT;
153 case kCondLE: return LE;
154 case kCondGT: return GT;
155 case kCondGE: return GE;
156 default:
157 LOG(FATAL) << "Unknown if condition";
158 }
159 return EQ; // Unreachable.
160}
161
162inline Condition ARMOppositeCondition(IfCondition cond) {
163 switch (cond) {
164 case kCondEQ: return NE;
165 case kCondNE: return EQ;
166 case kCondLT: return GE;
167 case kCondLE: return GT;
168 case kCondGT: return LE;
169 case kCondGE: return LT;
170 default:
171 LOG(FATAL) << "Unknown if condition";
172 }
173 return EQ; // Unreachable.
174}
175
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100176void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
177 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
178}
179
180void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
181 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
182}
183
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100184CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
185 : CodeGenerator(graph, kNumberOfRegIds),
186 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100187 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100188 move_resolver_(graph->GetArena(), this),
189 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100190
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100191size_t CodeGeneratorARM::FrameEntrySpillSize() const {
192 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
193}
194
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100195static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
196 return blocked_registers + kNumberOfAllocIds;
197}
198
199ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
200 bool* blocked_registers) const {
201 switch (type) {
202 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100203 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
204 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100205 ArmManagedRegister pair =
206 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
207 blocked_registers[pair.AsRegisterPairLow()] = true;
208 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100209 // Block all other register pairs that share a register with `pair`.
210 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
211 ArmManagedRegister current =
212 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
213 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
214 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
215 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
216 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
217 blocked_register_pairs[i] = true;
218 }
219 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100220 return pair;
221 }
222
223 case Primitive::kPrimByte:
224 case Primitive::kPrimBoolean:
225 case Primitive::kPrimChar:
226 case Primitive::kPrimShort:
227 case Primitive::kPrimInt:
228 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100229 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
230 // Block all register pairs that contain `reg`.
231 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
232 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
233 ArmManagedRegister current =
234 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
235 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
236 blocked_register_pairs[i] = true;
237 }
238 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100239 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
240 }
241
242 case Primitive::kPrimFloat:
243 case Primitive::kPrimDouble:
244 LOG(FATAL) << "Unimplemented register type " << type;
245
246 case Primitive::kPrimVoid:
247 LOG(FATAL) << "Unreachable type " << type;
248 }
249
250 return ManagedRegister::NoRegister();
251}
252
253void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
254 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
255
256 // Don't allocate the dalvik style register pair passing.
257 blocked_register_pairs[R1_R2] = true;
258
259 // Stack register, LR and PC are always reserved.
260 blocked_registers[SP] = true;
261 blocked_registers[LR] = true;
262 blocked_registers[PC] = true;
263
264 // Reserve R4 for suspend check.
265 blocked_registers[R4] = true;
266 blocked_register_pairs[R4_R5] = true;
267
268 // Reserve thread register.
269 blocked_registers[TR] = true;
270
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100271 // Reserve temp register.
272 blocked_registers[IP] = true;
273
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100274 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100275 // We always save and restore R6 and R7 to make sure we can use three
276 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100277 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100278 blocked_registers[R8] = true;
279 blocked_registers[R10] = true;
280 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100281}
282
283size_t CodeGeneratorARM::GetNumberOfRegisters() const {
284 return kNumberOfRegIds;
285}
286
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100287InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
288 : HGraphVisitor(graph),
289 assembler_(codegen->GetAssembler()),
290 codegen_(codegen) {}
291
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000292void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700293 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100294 if (!skip_overflow_check) {
295 if (kExplicitStackOverflowCheck) {
296 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
297 AddSlowPath(slow_path);
298
299 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
300 __ cmp(SP, ShifterOperand(IP));
301 __ b(slow_path->GetEntryLabel(), CC);
302 } else {
303 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
304 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100305 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100306 }
307 }
308
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100309 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
310 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000311
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100312 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100313 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000314 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000315}
316
317void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100318 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100319 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000320}
321
322void CodeGeneratorARM::Bind(Label* label) {
323 __ Bind(label);
324}
325
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100326Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
327 switch (load->GetType()) {
328 case Primitive::kPrimLong:
329 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
330 break;
331
332 case Primitive::kPrimInt:
333 case Primitive::kPrimNot:
334 return Location::StackSlot(GetStackSlot(load->GetLocal()));
335
336 case Primitive::kPrimFloat:
337 case Primitive::kPrimDouble:
338 LOG(FATAL) << "Unimplemented type " << load->GetType();
339
340 case Primitive::kPrimBoolean:
341 case Primitive::kPrimByte:
342 case Primitive::kPrimChar:
343 case Primitive::kPrimShort:
344 case Primitive::kPrimVoid:
345 LOG(FATAL) << "Unexpected type " << load->GetType();
346 }
347
348 LOG(FATAL) << "Unreachable";
349 return Location();
350}
351
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100352Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
353 switch (type) {
354 case Primitive::kPrimBoolean:
355 case Primitive::kPrimByte:
356 case Primitive::kPrimChar:
357 case Primitive::kPrimShort:
358 case Primitive::kPrimInt:
359 case Primitive::kPrimNot: {
360 uint32_t index = gp_index_++;
361 if (index < calling_convention.GetNumberOfRegisters()) {
362 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
363 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100364 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100365 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100366 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100367
368 case Primitive::kPrimLong: {
369 uint32_t index = gp_index_;
370 gp_index_ += 2;
371 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
372 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
373 calling_convention.GetRegisterPairAt(index)));
374 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
375 return Location::QuickParameter(index);
376 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100377 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100378 }
379 }
380
381 case Primitive::kPrimDouble:
382 case Primitive::kPrimFloat:
383 LOG(FATAL) << "Unimplemented parameter type " << type;
384 break;
385
386 case Primitive::kPrimVoid:
387 LOG(FATAL) << "Unexpected parameter type " << type;
388 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100389 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100390 return Location();
391}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100392
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100393void CodeGeneratorARM::Move32(Location destination, Location source) {
394 if (source.Equals(destination)) {
395 return;
396 }
397 if (destination.IsRegister()) {
398 if (source.IsRegister()) {
399 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
400 } else {
401 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
402 }
403 } else {
404 DCHECK(destination.IsStackSlot());
405 if (source.IsRegister()) {
406 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
407 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100408 __ ldr(IP, Address(SP, source.GetStackIndex()));
409 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100410 }
411 }
412}
413
414void CodeGeneratorARM::Move64(Location destination, Location source) {
415 if (source.Equals(destination)) {
416 return;
417 }
418 if (destination.IsRegister()) {
419 if (source.IsRegister()) {
420 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
421 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
422 } else if (source.IsQuickParameter()) {
423 uint32_t argument_index = source.GetQuickParameterIndex();
424 InvokeDexCallingConvention calling_convention;
425 __ Mov(destination.AsArm().AsRegisterPairLow(),
426 calling_convention.GetRegisterAt(argument_index));
427 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100428 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100429 } else {
430 DCHECK(source.IsDoubleStackSlot());
431 if (destination.AsArm().AsRegisterPair() == R1_R2) {
432 __ ldr(R1, Address(SP, source.GetStackIndex()));
433 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
434 } else {
435 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
436 SP, source.GetStackIndex());
437 }
438 }
439 } else if (destination.IsQuickParameter()) {
440 InvokeDexCallingConvention calling_convention;
441 uint32_t argument_index = destination.GetQuickParameterIndex();
442 if (source.IsRegister()) {
443 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
444 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100445 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100446 } else {
447 DCHECK(source.IsDoubleStackSlot());
448 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100449 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
450 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100451 }
452 } else {
453 DCHECK(destination.IsDoubleStackSlot());
454 if (source.IsRegister()) {
455 if (source.AsArm().AsRegisterPair() == R1_R2) {
456 __ str(R1, Address(SP, destination.GetStackIndex()));
457 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
458 } else {
459 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
460 SP, destination.GetStackIndex());
461 }
462 } else if (source.IsQuickParameter()) {
463 InvokeDexCallingConvention calling_convention;
464 uint32_t argument_index = source.GetQuickParameterIndex();
465 __ str(calling_convention.GetRegisterAt(argument_index),
466 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100467 __ ldr(R0,
468 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
469 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100470 } else {
471 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100472 __ ldr(IP, Address(SP, source.GetStackIndex()));
473 __ str(IP, Address(SP, destination.GetStackIndex()));
474 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
475 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100476 }
477 }
478}
479
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100480void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100481 LocationSummary* locations = instruction->GetLocations();
482 if (locations != nullptr && locations->Out().Equals(location)) {
483 return;
484 }
485
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100486 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100487 int32_t value = instruction->AsIntConstant()->GetValue();
488 if (location.IsRegister()) {
489 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
490 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100491 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100492 __ LoadImmediate(IP, value);
493 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100494 }
495 } else if (instruction->AsLongConstant() != nullptr) {
496 int64_t value = instruction->AsLongConstant()->GetValue();
497 if (location.IsRegister()) {
498 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
499 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
500 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100501 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100502 __ LoadImmediate(IP, Low32Bits(value));
503 __ str(IP, Address(SP, location.GetStackIndex()));
504 __ LoadImmediate(IP, High32Bits(value));
505 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100506 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100507 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100508 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
509 switch (instruction->GetType()) {
510 case Primitive::kPrimBoolean:
511 case Primitive::kPrimByte:
512 case Primitive::kPrimChar:
513 case Primitive::kPrimShort:
514 case Primitive::kPrimInt:
515 case Primitive::kPrimNot:
516 Move32(location, Location::StackSlot(stack_slot));
517 break;
518
519 case Primitive::kPrimLong:
520 Move64(location, Location::DoubleStackSlot(stack_slot));
521 break;
522
523 default:
524 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
525 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000526 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100527 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100528 switch (instruction->GetType()) {
529 case Primitive::kPrimBoolean:
530 case Primitive::kPrimByte:
531 case Primitive::kPrimChar:
532 case Primitive::kPrimShort:
533 case Primitive::kPrimNot:
534 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100535 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100536 break;
537
538 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100539 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100540 break;
541
542 default:
543 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
544 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000545 }
546}
547
548void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000549 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000550}
551
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000552void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000553 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000554 if (GetGraph()->GetExitBlock() == successor) {
555 codegen_->GenerateFrameExit();
556 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
557 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000558 }
559}
560
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000561void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000562 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000563}
564
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000565void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000566 if (kIsDebugBuild) {
567 __ Comment("Unreachable");
568 __ bkpt(0);
569 }
570}
571
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000572void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100573 LocationSummary* locations =
574 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100575 HInstruction* cond = if_instr->InputAt(0);
576 DCHECK(cond->IsCondition());
577 HCondition* condition = cond->AsCondition();
578 if (condition->NeedsMaterialization()) {
579 locations->SetInAt(0, Location::Any());
580 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000581}
582
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000583void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700584 HInstruction* cond = if_instr->InputAt(0);
585 DCHECK(cond->IsCondition());
586 HCondition* condition = cond->AsCondition();
587 if (condition->NeedsMaterialization()) {
588 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100589 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700590 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
591 ShifterOperand(0));
592 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
593 } else {
594 // Condition has not been materialized, use its inputs as the comparison and its
595 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100596 LocationSummary* locations = condition->GetLocations();
597 if (locations->InAt(1).IsRegister()) {
598 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
599 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
600 } else {
601 DCHECK(locations->InAt(1).IsConstant());
602 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
603 ShifterOperand operand;
604 if (ShifterOperand::CanHoldArm(value, &operand)) {
605 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
606 } else {
607 Register temp = IP;
608 __ LoadImmediate(temp, value);
609 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
610 }
611 }
Dave Allison20dfc792014-06-16 20:44:29 -0700612 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
613 ARMCondition(condition->GetCondition()));
614 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100615
Dave Allison20dfc792014-06-16 20:44:29 -0700616 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
617 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000618 }
619}
620
Dave Allison20dfc792014-06-16 20:44:29 -0700621
622void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100623 LocationSummary* locations =
624 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100625 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100626 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100627 if (comp->NeedsMaterialization()) {
628 locations->SetOut(Location::RequiresRegister());
629 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000630}
631
Dave Allison20dfc792014-06-16 20:44:29 -0700632void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100633 if (!comp->NeedsMaterialization()) return;
634
635 LocationSummary* locations = comp->GetLocations();
636 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700637 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
638 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100639 } else {
640 DCHECK(locations->InAt(1).IsConstant());
641 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
642 ShifterOperand operand;
643 if (ShifterOperand::CanHoldArm(value, &operand)) {
644 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
645 } else {
646 Register temp = IP;
647 __ LoadImmediate(temp, value);
648 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
649 }
Dave Allison20dfc792014-06-16 20:44:29 -0700650 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100651 __ it(ARMCondition(comp->GetCondition()), kItElse);
652 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
653 ARMCondition(comp->GetCondition()));
654 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
655 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700656}
657
658void LocationsBuilderARM::VisitEqual(HEqual* comp) {
659 VisitCondition(comp);
660}
661
662void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
663 VisitCondition(comp);
664}
665
666void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
667 VisitCondition(comp);
668}
669
670void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
671 VisitCondition(comp);
672}
673
674void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
675 VisitCondition(comp);
676}
677
678void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
679 VisitCondition(comp);
680}
681
682void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
683 VisitCondition(comp);
684}
685
686void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
687 VisitCondition(comp);
688}
689
690void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
691 VisitCondition(comp);
692}
693
694void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
695 VisitCondition(comp);
696}
697
698void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
699 VisitCondition(comp);
700}
701
702void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
703 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000704}
705
706void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000707 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000708}
709
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000710void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
711 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000712}
713
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000714void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100715 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000716}
717
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000718void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100719 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000720}
721
722void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100723 LocationSummary* locations =
724 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100725 switch (store->InputAt(1)->GetType()) {
726 case Primitive::kPrimBoolean:
727 case Primitive::kPrimByte:
728 case Primitive::kPrimChar:
729 case Primitive::kPrimShort:
730 case Primitive::kPrimInt:
731 case Primitive::kPrimNot:
732 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
733 break;
734
735 case Primitive::kPrimLong:
736 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
737 break;
738
739 default:
740 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
741 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000742}
743
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000744void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000745}
746
747void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100748 LocationSummary* locations =
749 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100750 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000751}
752
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000753void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000754}
755
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100756void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100757 LocationSummary* locations =
758 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100759 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100760}
761
762void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
763 // Will be generated at use site.
764}
765
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000766void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000767 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000768}
769
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000770void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
771 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000772}
773
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000774void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100775 LocationSummary* locations =
776 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100777 switch (ret->InputAt(0)->GetType()) {
778 case Primitive::kPrimBoolean:
779 case Primitive::kPrimByte:
780 case Primitive::kPrimChar:
781 case Primitive::kPrimShort:
782 case Primitive::kPrimInt:
783 case Primitive::kPrimNot:
784 locations->SetInAt(0, ArmCoreLocation(R0));
785 break;
786
787 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100788 locations->SetInAt(
789 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100790 break;
791
792 default:
793 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
794 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000795}
796
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000797void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100798 if (kIsDebugBuild) {
799 switch (ret->InputAt(0)->GetType()) {
800 case Primitive::kPrimBoolean:
801 case Primitive::kPrimByte:
802 case Primitive::kPrimChar:
803 case Primitive::kPrimShort:
804 case Primitive::kPrimInt:
805 case Primitive::kPrimNot:
806 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
807 break;
808
809 case Primitive::kPrimLong:
810 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
811 break;
812
813 default:
814 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
815 }
816 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000817 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000818}
819
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000820void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100821 LocationSummary* locations =
822 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100823 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100824
825 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100826 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100827 HInstruction* input = invoke->InputAt(i);
828 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
829 }
830
831 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100832 case Primitive::kPrimBoolean:
833 case Primitive::kPrimByte:
834 case Primitive::kPrimChar:
835 case Primitive::kPrimShort:
836 case Primitive::kPrimInt:
837 case Primitive::kPrimNot:
838 locations->SetOut(ArmCoreLocation(R0));
839 break;
840
841 case Primitive::kPrimLong:
842 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
843 break;
844
845 case Primitive::kPrimVoid:
846 break;
847
848 case Primitive::kPrimDouble:
849 case Primitive::kPrimFloat:
850 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
851 break;
852 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000853}
854
855void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100856 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000857}
858
859void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100860 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100861 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
862 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100863 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000864
865 // TODO: Implement all kinds of calls:
866 // 1) boot -> boot
867 // 2) app -> boot
868 // 3) app -> app
869 //
870 // Currently we implement the app -> app logic, which looks up in the resolve cache.
871
872 // temp = method;
873 LoadCurrentMethod(temp);
874 // temp = temp->dex_cache_resolved_methods_;
875 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
876 // temp = temp[index_in_cache]
877 __ ldr(temp, Address(temp, index_in_cache));
878 // LR = temp[offset_of_quick_compiled_code]
879 __ ldr(LR, Address(temp,
880 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
881 // LR()
882 __ blx(LR);
883
Nicolas Geoffray39468442014-09-02 15:17:15 +0100884 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100885 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000886}
887
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000888void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100889 LocationSummary* locations =
890 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000891 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100892 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100893 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100894 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100895 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100896 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100897 break;
898 }
899
900 case Primitive::kPrimBoolean:
901 case Primitive::kPrimByte:
902 case Primitive::kPrimChar:
903 case Primitive::kPrimShort:
904 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
905 break;
906
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000907 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100908 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000909 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000910}
911
912void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
913 LocationSummary* locations = add->GetLocations();
914 switch (add->GetResultType()) {
915 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100916 if (locations->InAt(1).IsRegister()) {
917 __ add(locations->Out().AsArm().AsCoreRegister(),
918 locations->InAt(0).AsArm().AsCoreRegister(),
919 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
920 } else {
921 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
922 locations->InAt(0).AsArm().AsCoreRegister(),
923 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
924 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000925 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100926
927 case Primitive::kPrimLong:
928 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
929 locations->InAt(0).AsArm().AsRegisterPairLow(),
930 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
931 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
932 locations->InAt(0).AsArm().AsRegisterPairHigh(),
933 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
934 break;
935
936 case Primitive::kPrimBoolean:
937 case Primitive::kPrimByte:
938 case Primitive::kPrimChar:
939 case Primitive::kPrimShort:
940 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
941 break;
942
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000943 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100944 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000945 }
946}
947
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100948void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100949 LocationSummary* locations =
950 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100951 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100952 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100953 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100954 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100955 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100956 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100957 break;
958 }
959
960 case Primitive::kPrimBoolean:
961 case Primitive::kPrimByte:
962 case Primitive::kPrimChar:
963 case Primitive::kPrimShort:
964 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
965 break;
966
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100967 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100968 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100969 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100970}
971
972void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
973 LocationSummary* locations = sub->GetLocations();
974 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100975 case Primitive::kPrimInt: {
976 if (locations->InAt(1).IsRegister()) {
977 __ sub(locations->Out().AsArm().AsCoreRegister(),
978 locations->InAt(0).AsArm().AsCoreRegister(),
979 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
980 } else {
981 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
982 locations->InAt(0).AsArm().AsCoreRegister(),
983 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
984 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100985 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100986 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100987
988 case Primitive::kPrimLong:
989 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
990 locations->InAt(0).AsArm().AsRegisterPairLow(),
991 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
992 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
993 locations->InAt(0).AsArm().AsRegisterPairHigh(),
994 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
995 break;
996
997 case Primitive::kPrimBoolean:
998 case Primitive::kPrimByte:
999 case Primitive::kPrimChar:
1000 case Primitive::kPrimShort:
1001 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1002 break;
1003
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001004 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001005 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001006 }
1007}
1008
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001009void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001010 LocationSummary* locations =
1011 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001012 InvokeRuntimeCallingConvention calling_convention;
1013 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1014 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001015 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001016}
1017
1018void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1019 InvokeRuntimeCallingConvention calling_convention;
1020 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1021 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1022
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001023 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001024 __ ldr(LR, Address(TR, offset));
1025 __ blx(LR);
1026
Nicolas Geoffray39468442014-09-02 15:17:15 +01001027 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001028 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001029}
1030
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001031void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001032 LocationSummary* locations =
1033 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001034 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1035 if (location.IsStackSlot()) {
1036 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1037 } else if (location.IsDoubleStackSlot()) {
1038 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001039 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001040 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001041}
1042
1043void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001044 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001045}
1046
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001047void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001048 LocationSummary* locations =
1049 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001050 locations->SetInAt(0, Location::RequiresRegister());
1051 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001052}
1053
1054void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1055 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001056 __ eor(locations->Out().AsArm().AsCoreRegister(),
1057 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001058}
1059
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001060void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001061 LocationSummary* locations =
1062 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001063 locations->SetInAt(0, Location::RequiresRegister());
1064 locations->SetInAt(1, Location::RequiresRegister());
1065 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001066}
1067
1068void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1069 Label greater, done;
1070 LocationSummary* locations = compare->GetLocations();
1071 switch (compare->InputAt(0)->GetType()) {
1072 case Primitive::kPrimLong: {
1073 Register output = locations->Out().AsArm().AsCoreRegister();
1074 ArmManagedRegister left = locations->InAt(0).AsArm();
1075 ArmManagedRegister right = locations->InAt(1).AsArm();
1076 Label less, greater, done;
1077 __ cmp(left.AsRegisterPairHigh(),
1078 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1079 __ b(&less, LT);
1080 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001081 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1082 // the status flags.
1083 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001084 __ cmp(left.AsRegisterPairLow(),
1085 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001086 __ b(&done, EQ);
1087 __ b(&less, CC);
1088
1089 __ Bind(&greater);
1090 __ LoadImmediate(output, 1);
1091 __ b(&done);
1092
1093 __ Bind(&less);
1094 __ LoadImmediate(output, -1);
1095
1096 __ Bind(&done);
1097 break;
1098 }
1099 default:
1100 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1101 }
1102}
1103
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001104void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001105 LocationSummary* locations =
1106 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001107 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1108 locations->SetInAt(i, Location::Any());
1109 }
1110 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001111}
1112
1113void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001114 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001115}
1116
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001117void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001118 LocationSummary* locations =
1119 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001120 locations->SetInAt(0, Location::RequiresRegister());
1121 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001122 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001123 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001124 locations->AddTemp(Location::RequiresRegister());
1125 locations->AddTemp(Location::RequiresRegister());
1126 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001127}
1128
1129void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1130 LocationSummary* locations = instruction->GetLocations();
1131 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1132 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001133 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001134
1135 switch (field_type) {
1136 case Primitive::kPrimBoolean:
1137 case Primitive::kPrimByte: {
1138 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1139 __ StoreToOffset(kStoreByte, value, obj, offset);
1140 break;
1141 }
1142
1143 case Primitive::kPrimShort:
1144 case Primitive::kPrimChar: {
1145 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1146 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1147 break;
1148 }
1149
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001150 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001151 case Primitive::kPrimNot: {
1152 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1153 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001154 if (field_type == Primitive::kPrimNot) {
1155 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1156 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1157 codegen_->MarkGCCard(temp, card, obj, value);
1158 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001159 break;
1160 }
1161
1162 case Primitive::kPrimLong: {
1163 ArmManagedRegister value = locations->InAt(1).AsArm();
1164 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1165 break;
1166 }
1167
1168 case Primitive::kPrimFloat:
1169 case Primitive::kPrimDouble:
1170 LOG(FATAL) << "Unimplemented register type " << field_type;
1171
1172 case Primitive::kPrimVoid:
1173 LOG(FATAL) << "Unreachable type " << field_type;
1174 }
1175}
1176
1177void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001178 LocationSummary* locations =
1179 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001180 locations->SetInAt(0, Location::RequiresRegister());
1181 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001182}
1183
1184void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1185 LocationSummary* locations = instruction->GetLocations();
1186 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1187 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1188
1189 switch (instruction->GetType()) {
1190 case Primitive::kPrimBoolean: {
1191 Register out = locations->Out().AsArm().AsCoreRegister();
1192 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1193 break;
1194 }
1195
1196 case Primitive::kPrimByte: {
1197 Register out = locations->Out().AsArm().AsCoreRegister();
1198 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1199 break;
1200 }
1201
1202 case Primitive::kPrimShort: {
1203 Register out = locations->Out().AsArm().AsCoreRegister();
1204 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1205 break;
1206 }
1207
1208 case Primitive::kPrimChar: {
1209 Register out = locations->Out().AsArm().AsCoreRegister();
1210 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1211 break;
1212 }
1213
1214 case Primitive::kPrimInt:
1215 case Primitive::kPrimNot: {
1216 Register out = locations->Out().AsArm().AsCoreRegister();
1217 __ LoadFromOffset(kLoadWord, out, obj, offset);
1218 break;
1219 }
1220
1221 case Primitive::kPrimLong: {
1222 // TODO: support volatile.
1223 ArmManagedRegister out = locations->Out().AsArm();
1224 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1225 break;
1226 }
1227
1228 case Primitive::kPrimFloat:
1229 case Primitive::kPrimDouble:
1230 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1231
1232 case Primitive::kPrimVoid:
1233 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1234 }
1235}
1236
1237void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001238 LocationSummary* locations =
1239 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001240 locations->SetInAt(0, Location::RequiresRegister());
1241 // TODO: Have a normalization phase that makes this instruction never used.
1242 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001243}
1244
1245void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001246 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001247 codegen_->AddSlowPath(slow_path);
1248
1249 LocationSummary* locations = instruction->GetLocations();
1250 Location obj = locations->InAt(0);
1251 DCHECK(obj.Equals(locations->Out()));
1252
1253 if (obj.IsRegister()) {
1254 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1255 }
1256 __ b(slow_path->GetEntryLabel(), EQ);
1257}
1258
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001259void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001260 LocationSummary* locations =
1261 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001262 locations->SetInAt(0, Location::RequiresRegister());
1263 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1264 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001265}
1266
1267void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1268 LocationSummary* locations = instruction->GetLocations();
1269 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1270 Location index = locations->InAt(1);
1271
1272 switch (instruction->GetType()) {
1273 case Primitive::kPrimBoolean: {
1274 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1275 Register out = locations->Out().AsArm().AsCoreRegister();
1276 if (index.IsConstant()) {
1277 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1278 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1279 } else {
1280 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1281 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1282 }
1283 break;
1284 }
1285
1286 case Primitive::kPrimByte: {
1287 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1288 Register out = locations->Out().AsArm().AsCoreRegister();
1289 if (index.IsConstant()) {
1290 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1291 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1292 } else {
1293 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1294 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1295 }
1296 break;
1297 }
1298
1299 case Primitive::kPrimShort: {
1300 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1301 Register out = locations->Out().AsArm().AsCoreRegister();
1302 if (index.IsConstant()) {
1303 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1304 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1305 } else {
1306 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1307 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1308 }
1309 break;
1310 }
1311
1312 case Primitive::kPrimChar: {
1313 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1314 Register out = locations->Out().AsArm().AsCoreRegister();
1315 if (index.IsConstant()) {
1316 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1317 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1318 } else {
1319 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1320 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1321 }
1322 break;
1323 }
1324
1325 case Primitive::kPrimInt:
1326 case Primitive::kPrimNot: {
1327 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1328 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1329 Register out = locations->Out().AsArm().AsCoreRegister();
1330 if (index.IsConstant()) {
1331 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1332 __ LoadFromOffset(kLoadWord, out, obj, offset);
1333 } else {
1334 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1335 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1336 }
1337 break;
1338 }
1339
1340 case Primitive::kPrimLong: {
1341 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1342 ArmManagedRegister out = locations->Out().AsArm();
1343 if (index.IsConstant()) {
1344 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1345 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1346 } else {
1347 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1348 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1349 }
1350 break;
1351 }
1352
1353 case Primitive::kPrimFloat:
1354 case Primitive::kPrimDouble:
1355 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1356
1357 case Primitive::kPrimVoid:
1358 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1359 }
1360}
1361
1362void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001363 Primitive::Type value_type = instruction->GetComponentType();
1364 bool is_object = value_type == Primitive::kPrimNot;
1365 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1366 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1367 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001368 InvokeRuntimeCallingConvention calling_convention;
1369 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1370 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1371 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001372 } else {
1373 locations->SetInAt(0, Location::RequiresRegister());
1374 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1375 locations->SetInAt(2, Location::RequiresRegister());
1376 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001377}
1378
1379void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1380 LocationSummary* locations = instruction->GetLocations();
1381 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1382 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001383 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001384
1385 switch (value_type) {
1386 case Primitive::kPrimBoolean:
1387 case Primitive::kPrimByte: {
1388 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1389 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1390 if (index.IsConstant()) {
1391 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1392 __ StoreToOffset(kStoreByte, value, obj, offset);
1393 } else {
1394 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1395 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1396 }
1397 break;
1398 }
1399
1400 case Primitive::kPrimShort:
1401 case Primitive::kPrimChar: {
1402 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1403 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1404 if (index.IsConstant()) {
1405 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1406 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1407 } else {
1408 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1409 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1410 }
1411 break;
1412 }
1413
1414 case Primitive::kPrimInt: {
1415 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1416 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1417 if (index.IsConstant()) {
1418 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1419 __ StoreToOffset(kStoreWord, value, obj, offset);
1420 } else {
1421 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1422 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1423 }
1424 break;
1425 }
1426
1427 case Primitive::kPrimNot: {
1428 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1429 __ ldr(LR, Address(TR, offset));
1430 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001431 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001432 DCHECK(!codegen_->IsLeafMethod());
1433 break;
1434 }
1435
1436 case Primitive::kPrimLong: {
1437 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1438 ArmManagedRegister value = locations->InAt(2).AsArm();
1439 if (index.IsConstant()) {
1440 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1441 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1442 } else {
1443 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1444 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1445 }
1446 break;
1447 }
1448
1449 case Primitive::kPrimFloat:
1450 case Primitive::kPrimDouble:
1451 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1452
1453 case Primitive::kPrimVoid:
1454 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1455 }
1456}
1457
1458void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001459 LocationSummary* locations =
1460 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001461 locations->SetInAt(0, Location::RequiresRegister());
1462 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001463}
1464
1465void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1466 LocationSummary* locations = instruction->GetLocations();
1467 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1468 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1469 Register out = locations->Out().AsArm().AsCoreRegister();
1470 __ LoadFromOffset(kLoadWord, out, obj, offset);
1471}
1472
1473void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001474 LocationSummary* locations =
1475 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001476 locations->SetInAt(0, Location::RequiresRegister());
1477 locations->SetInAt(1, Location::RequiresRegister());
1478 // TODO: Have a normalization phase that makes this instruction never used.
1479 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001480}
1481
1482void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1483 LocationSummary* locations = instruction->GetLocations();
1484 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001485 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001486 codegen_->AddSlowPath(slow_path);
1487
1488 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1489 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1490
1491 __ cmp(index, ShifterOperand(length));
1492 __ b(slow_path->GetEntryLabel(), CS);
1493}
1494
1495void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1496 Label is_null;
1497 __ CompareAndBranchIfZero(value, &is_null);
1498 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1499 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1500 __ strb(card, Address(card, temp));
1501 __ Bind(&is_null);
1502}
1503
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001504void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1505 temp->SetLocations(nullptr);
1506}
1507
1508void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1509 // Nothing to do, this is driven by the code generator.
1510}
1511
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001512void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001513 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001514}
1515
1516void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001517 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1518}
1519
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001520void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1521 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1522}
1523
1524void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1525 SuspendCheckSlowPathARM* slow_path =
1526 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction);
1527 codegen_->AddSlowPath(slow_path);
1528
1529 __ AddConstant(R4, R4, -1);
1530 __ cmp(R4, ShifterOperand(0));
1531 __ b(slow_path->GetEntryLabel(), LE);
1532 __ Bind(slow_path->GetReturnLabel());
1533}
1534
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001535ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1536 return codegen_->GetAssembler();
1537}
1538
1539void ParallelMoveResolverARM::EmitMove(size_t index) {
1540 MoveOperands* move = moves_.Get(index);
1541 Location source = move->GetSource();
1542 Location destination = move->GetDestination();
1543
1544 if (source.IsRegister()) {
1545 if (destination.IsRegister()) {
1546 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1547 } else {
1548 DCHECK(destination.IsStackSlot());
1549 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1550 SP, destination.GetStackIndex());
1551 }
1552 } else if (source.IsStackSlot()) {
1553 if (destination.IsRegister()) {
1554 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1555 SP, source.GetStackIndex());
1556 } else {
1557 DCHECK(destination.IsStackSlot());
1558 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1559 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1560 }
1561 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001562 DCHECK(source.IsConstant());
1563 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1564 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1565 if (destination.IsRegister()) {
1566 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1567 } else {
1568 DCHECK(destination.IsStackSlot());
1569 __ LoadImmediate(IP, value);
1570 __ str(IP, Address(SP, destination.GetStackIndex()));
1571 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001572 }
1573}
1574
1575void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1576 __ Mov(IP, reg);
1577 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1578 __ StoreToOffset(kStoreWord, IP, SP, mem);
1579}
1580
1581void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1582 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1583 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1584 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1585 SP, mem1 + stack_offset);
1586 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1587 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1588 SP, mem2 + stack_offset);
1589 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1590}
1591
1592void ParallelMoveResolverARM::EmitSwap(size_t index) {
1593 MoveOperands* move = moves_.Get(index);
1594 Location source = move->GetSource();
1595 Location destination = move->GetDestination();
1596
1597 if (source.IsRegister() && destination.IsRegister()) {
1598 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1599 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1600 __ Mov(IP, source.AsArm().AsCoreRegister());
1601 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1602 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1603 } else if (source.IsRegister() && destination.IsStackSlot()) {
1604 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1605 } else if (source.IsStackSlot() && destination.IsRegister()) {
1606 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1607 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1608 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1609 } else {
1610 LOG(FATAL) << "Unimplemented";
1611 }
1612}
1613
1614void ParallelMoveResolverARM::SpillScratch(int reg) {
1615 __ Push(static_cast<Register>(reg));
1616}
1617
1618void ParallelMoveResolverARM::RestoreScratch(int reg) {
1619 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001620}
1621
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001622} // namespace arm
1623} // namespace art