blob: eccc970042a6e8a70e9166212c1fa24b4965b6dc [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:
64 explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
65
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);
71 codegen->RecordPcInfo(dex_pc_);
72 }
73
74 private:
75 const uint32_t dex_pc_;
76 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 Geoffray3c7bb982014-07-23 16:04:16 +010093class BoundsCheckSlowPathARM : public SlowPathCode {
94 public:
95 explicit BoundsCheckSlowPathARM(uint32_t dex_pc,
96 Location index_location,
97 Location length_location)
98 : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
99
100 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
101 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
102 __ Bind(GetEntryLabel());
103 InvokeRuntimeCallingConvention calling_convention;
104 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
105 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
106 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
107 __ ldr(LR, Address(TR, offset));
108 __ blx(LR);
109 codegen->RecordPcInfo(dex_pc_);
110 }
111
112 private:
113 const uint32_t dex_pc_;
114 const Location index_location_;
115 const Location length_location_;
116
117 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
118};
119
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100120#undef __
121#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700122
123inline Condition ARMCondition(IfCondition cond) {
124 switch (cond) {
125 case kCondEQ: return EQ;
126 case kCondNE: return NE;
127 case kCondLT: return LT;
128 case kCondLE: return LE;
129 case kCondGT: return GT;
130 case kCondGE: return GE;
131 default:
132 LOG(FATAL) << "Unknown if condition";
133 }
134 return EQ; // Unreachable.
135}
136
137inline Condition ARMOppositeCondition(IfCondition cond) {
138 switch (cond) {
139 case kCondEQ: return NE;
140 case kCondNE: return EQ;
141 case kCondLT: return GE;
142 case kCondLE: return GT;
143 case kCondGT: return LE;
144 case kCondGE: return LT;
145 default:
146 LOG(FATAL) << "Unknown if condition";
147 }
148 return EQ; // Unreachable.
149}
150
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100151void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
152 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
153}
154
155void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
156 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
157}
158
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100159CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
160 : CodeGenerator(graph, kNumberOfRegIds),
161 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100162 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100163 move_resolver_(graph->GetArena(), this),
164 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100165
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100166size_t CodeGeneratorARM::FrameEntrySpillSize() const {
167 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
168}
169
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100170static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
171 return blocked_registers + kNumberOfAllocIds;
172}
173
174ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
175 bool* blocked_registers) const {
176 switch (type) {
177 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100178 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
179 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100180 ArmManagedRegister pair =
181 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
182 blocked_registers[pair.AsRegisterPairLow()] = true;
183 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100184 // Block all other register pairs that share a register with `pair`.
185 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
186 ArmManagedRegister current =
187 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
188 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
189 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
190 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
191 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
192 blocked_register_pairs[i] = true;
193 }
194 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100195 return pair;
196 }
197
198 case Primitive::kPrimByte:
199 case Primitive::kPrimBoolean:
200 case Primitive::kPrimChar:
201 case Primitive::kPrimShort:
202 case Primitive::kPrimInt:
203 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100204 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
205 // Block all register pairs that contain `reg`.
206 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
207 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
208 ArmManagedRegister current =
209 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
210 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
211 blocked_register_pairs[i] = true;
212 }
213 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100214 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
215 }
216
217 case Primitive::kPrimFloat:
218 case Primitive::kPrimDouble:
219 LOG(FATAL) << "Unimplemented register type " << type;
220
221 case Primitive::kPrimVoid:
222 LOG(FATAL) << "Unreachable type " << type;
223 }
224
225 return ManagedRegister::NoRegister();
226}
227
228void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
229 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
230
231 // Don't allocate the dalvik style register pair passing.
232 blocked_register_pairs[R1_R2] = true;
233
234 // Stack register, LR and PC are always reserved.
235 blocked_registers[SP] = true;
236 blocked_registers[LR] = true;
237 blocked_registers[PC] = true;
238
239 // Reserve R4 for suspend check.
240 blocked_registers[R4] = true;
241 blocked_register_pairs[R4_R5] = true;
242
243 // Reserve thread register.
244 blocked_registers[TR] = true;
245
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100246 // Reserve temp register.
247 blocked_registers[IP] = true;
248
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100249 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100250 // We always save and restore R6 and R7 to make sure we can use three
251 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100252 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100253 blocked_registers[R8] = true;
254 blocked_registers[R10] = true;
255 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100256}
257
258size_t CodeGeneratorARM::GetNumberOfRegisters() const {
259 return kNumberOfRegIds;
260}
261
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100262InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
263 : HGraphVisitor(graph),
264 assembler_(codegen->GetAssembler()),
265 codegen_(codegen) {}
266
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000267void CodeGeneratorARM::GenerateFrameEntry() {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100268 bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kArm);
269 if (!skip_overflow_check) {
270 if (kExplicitStackOverflowCheck) {
271 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
272 AddSlowPath(slow_path);
273
274 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
275 __ cmp(SP, ShifterOperand(IP));
276 __ b(slow_path->GetEntryLabel(), CC);
277 } else {
278 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
279 __ ldr(IP, Address(IP, 0));
280 RecordPcInfo(0);
281 }
282 }
283
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100284 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
285 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000286
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100287 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100288 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000289 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000290}
291
292void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100293 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100294 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000295}
296
297void CodeGeneratorARM::Bind(Label* label) {
298 __ Bind(label);
299}
300
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100301Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
302 switch (load->GetType()) {
303 case Primitive::kPrimLong:
304 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
305 break;
306
307 case Primitive::kPrimInt:
308 case Primitive::kPrimNot:
309 return Location::StackSlot(GetStackSlot(load->GetLocal()));
310
311 case Primitive::kPrimFloat:
312 case Primitive::kPrimDouble:
313 LOG(FATAL) << "Unimplemented type " << load->GetType();
314
315 case Primitive::kPrimBoolean:
316 case Primitive::kPrimByte:
317 case Primitive::kPrimChar:
318 case Primitive::kPrimShort:
319 case Primitive::kPrimVoid:
320 LOG(FATAL) << "Unexpected type " << load->GetType();
321 }
322
323 LOG(FATAL) << "Unreachable";
324 return Location();
325}
326
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100327Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
328 switch (type) {
329 case Primitive::kPrimBoolean:
330 case Primitive::kPrimByte:
331 case Primitive::kPrimChar:
332 case Primitive::kPrimShort:
333 case Primitive::kPrimInt:
334 case Primitive::kPrimNot: {
335 uint32_t index = gp_index_++;
336 if (index < calling_convention.GetNumberOfRegisters()) {
337 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
338 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100339 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100340 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100341 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100342
343 case Primitive::kPrimLong: {
344 uint32_t index = gp_index_;
345 gp_index_ += 2;
346 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
347 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
348 calling_convention.GetRegisterPairAt(index)));
349 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
350 return Location::QuickParameter(index);
351 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100352 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100353 }
354 }
355
356 case Primitive::kPrimDouble:
357 case Primitive::kPrimFloat:
358 LOG(FATAL) << "Unimplemented parameter type " << type;
359 break;
360
361 case Primitive::kPrimVoid:
362 LOG(FATAL) << "Unexpected parameter type " << type;
363 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100364 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100365 return Location();
366}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100367
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100368void CodeGeneratorARM::Move32(Location destination, Location source) {
369 if (source.Equals(destination)) {
370 return;
371 }
372 if (destination.IsRegister()) {
373 if (source.IsRegister()) {
374 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
375 } else {
376 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
377 }
378 } else {
379 DCHECK(destination.IsStackSlot());
380 if (source.IsRegister()) {
381 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
382 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100383 __ ldr(IP, Address(SP, source.GetStackIndex()));
384 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100385 }
386 }
387}
388
389void CodeGeneratorARM::Move64(Location destination, Location source) {
390 if (source.Equals(destination)) {
391 return;
392 }
393 if (destination.IsRegister()) {
394 if (source.IsRegister()) {
395 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
396 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
397 } else if (source.IsQuickParameter()) {
398 uint32_t argument_index = source.GetQuickParameterIndex();
399 InvokeDexCallingConvention calling_convention;
400 __ Mov(destination.AsArm().AsRegisterPairLow(),
401 calling_convention.GetRegisterAt(argument_index));
402 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100403 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100404 } else {
405 DCHECK(source.IsDoubleStackSlot());
406 if (destination.AsArm().AsRegisterPair() == R1_R2) {
407 __ ldr(R1, Address(SP, source.GetStackIndex()));
408 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
409 } else {
410 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
411 SP, source.GetStackIndex());
412 }
413 }
414 } else if (destination.IsQuickParameter()) {
415 InvokeDexCallingConvention calling_convention;
416 uint32_t argument_index = destination.GetQuickParameterIndex();
417 if (source.IsRegister()) {
418 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
419 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100420 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100421 } else {
422 DCHECK(source.IsDoubleStackSlot());
423 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100424 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
425 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100426 }
427 } else {
428 DCHECK(destination.IsDoubleStackSlot());
429 if (source.IsRegister()) {
430 if (source.AsArm().AsRegisterPair() == R1_R2) {
431 __ str(R1, Address(SP, destination.GetStackIndex()));
432 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
433 } else {
434 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
435 SP, destination.GetStackIndex());
436 }
437 } else if (source.IsQuickParameter()) {
438 InvokeDexCallingConvention calling_convention;
439 uint32_t argument_index = source.GetQuickParameterIndex();
440 __ str(calling_convention.GetRegisterAt(argument_index),
441 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100442 __ ldr(R0,
443 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
444 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100445 } else {
446 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100447 __ ldr(IP, Address(SP, source.GetStackIndex()));
448 __ str(IP, Address(SP, destination.GetStackIndex()));
449 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
450 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100451 }
452 }
453}
454
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100455void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100456 LocationSummary* locations = instruction->GetLocations();
457 if (locations != nullptr && locations->Out().Equals(location)) {
458 return;
459 }
460
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100461 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100462 int32_t value = instruction->AsIntConstant()->GetValue();
463 if (location.IsRegister()) {
464 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
465 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100466 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100467 __ LoadImmediate(IP, value);
468 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100469 }
470 } else if (instruction->AsLongConstant() != nullptr) {
471 int64_t value = instruction->AsLongConstant()->GetValue();
472 if (location.IsRegister()) {
473 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
474 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
475 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100476 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100477 __ LoadImmediate(IP, Low32Bits(value));
478 __ str(IP, Address(SP, location.GetStackIndex()));
479 __ LoadImmediate(IP, High32Bits(value));
480 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100481 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100482 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100483 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
484 switch (instruction->GetType()) {
485 case Primitive::kPrimBoolean:
486 case Primitive::kPrimByte:
487 case Primitive::kPrimChar:
488 case Primitive::kPrimShort:
489 case Primitive::kPrimInt:
490 case Primitive::kPrimNot:
491 Move32(location, Location::StackSlot(stack_slot));
492 break;
493
494 case Primitive::kPrimLong:
495 Move64(location, Location::DoubleStackSlot(stack_slot));
496 break;
497
498 default:
499 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
500 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000501 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100502 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100503 switch (instruction->GetType()) {
504 case Primitive::kPrimBoolean:
505 case Primitive::kPrimByte:
506 case Primitive::kPrimChar:
507 case Primitive::kPrimShort:
508 case Primitive::kPrimNot:
509 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100510 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100511 break;
512
513 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100514 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100515 break;
516
517 default:
518 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
519 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000520 }
521}
522
523void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000524 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000525}
526
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000527void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000528 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000529 if (GetGraph()->GetExitBlock() == successor) {
530 codegen_->GenerateFrameExit();
531 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
532 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000533 }
534}
535
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000536void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000537 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000538}
539
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000540void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000541 if (kIsDebugBuild) {
542 __ Comment("Unreachable");
543 __ bkpt(0);
544 }
545}
546
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000547void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000548 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100549 HInstruction* cond = if_instr->InputAt(0);
550 DCHECK(cond->IsCondition());
551 HCondition* condition = cond->AsCondition();
552 if (condition->NeedsMaterialization()) {
553 locations->SetInAt(0, Location::Any());
554 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000555 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000556}
557
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000558void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700559 HInstruction* cond = if_instr->InputAt(0);
560 DCHECK(cond->IsCondition());
561 HCondition* condition = cond->AsCondition();
562 if (condition->NeedsMaterialization()) {
563 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100564 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700565 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
566 ShifterOperand(0));
567 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
568 } else {
569 // Condition has not been materialized, use its inputs as the comparison and its
570 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100571 LocationSummary* locations = condition->GetLocations();
572 if (locations->InAt(1).IsRegister()) {
573 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
574 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
575 } else {
576 DCHECK(locations->InAt(1).IsConstant());
577 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
578 ShifterOperand operand;
579 if (ShifterOperand::CanHoldArm(value, &operand)) {
580 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
581 } else {
582 Register temp = IP;
583 __ LoadImmediate(temp, value);
584 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
585 }
586 }
Dave Allison20dfc792014-06-16 20:44:29 -0700587 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
588 ARMCondition(condition->GetCondition()));
589 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100590
Dave Allison20dfc792014-06-16 20:44:29 -0700591 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
592 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000593 }
594}
595
Dave Allison20dfc792014-06-16 20:44:29 -0700596
597void LocationsBuilderARM::VisitCondition(HCondition* comp) {
598 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100599 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100600 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100601 if (comp->NeedsMaterialization()) {
602 locations->SetOut(Location::RequiresRegister());
603 }
Dave Allison20dfc792014-06-16 20:44:29 -0700604 comp->SetLocations(locations);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000605}
606
Dave Allison20dfc792014-06-16 20:44:29 -0700607void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100608 if (!comp->NeedsMaterialization()) return;
609
610 LocationSummary* locations = comp->GetLocations();
611 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700612 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
613 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100614 } else {
615 DCHECK(locations->InAt(1).IsConstant());
616 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
617 ShifterOperand operand;
618 if (ShifterOperand::CanHoldArm(value, &operand)) {
619 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
620 } else {
621 Register temp = IP;
622 __ LoadImmediate(temp, value);
623 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
624 }
Dave Allison20dfc792014-06-16 20:44:29 -0700625 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100626 __ it(ARMCondition(comp->GetCondition()), kItElse);
627 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
628 ARMCondition(comp->GetCondition()));
629 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
630 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700631}
632
633void LocationsBuilderARM::VisitEqual(HEqual* comp) {
634 VisitCondition(comp);
635}
636
637void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
638 VisitCondition(comp);
639}
640
641void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
642 VisitCondition(comp);
643}
644
645void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
646 VisitCondition(comp);
647}
648
649void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
650 VisitCondition(comp);
651}
652
653void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
654 VisitCondition(comp);
655}
656
657void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
658 VisitCondition(comp);
659}
660
661void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
662 VisitCondition(comp);
663}
664
665void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
666 VisitCondition(comp);
667}
668
669void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
670 VisitCondition(comp);
671}
672
673void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
674 VisitCondition(comp);
675}
676
677void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
678 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000679}
680
681void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000682 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000683}
684
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000685void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
686 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000687}
688
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000689void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100690 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000691}
692
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000693void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100694 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000695}
696
697void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000698 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 switch (store->InputAt(1)->GetType()) {
700 case Primitive::kPrimBoolean:
701 case Primitive::kPrimByte:
702 case Primitive::kPrimChar:
703 case Primitive::kPrimShort:
704 case Primitive::kPrimInt:
705 case Primitive::kPrimNot:
706 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
707 break;
708
709 case Primitive::kPrimLong:
710 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
711 break;
712
713 default:
714 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
715 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000716 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000717}
718
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000719void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000720}
721
722void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100723 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100724 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100725 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000726}
727
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000728void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000729}
730
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100732 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100733 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100734 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100735}
736
737void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
738 // Will be generated at use site.
739}
740
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000741void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000742 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000743}
744
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000745void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
746 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000747}
748
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000749void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000750 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100751 switch (ret->InputAt(0)->GetType()) {
752 case Primitive::kPrimBoolean:
753 case Primitive::kPrimByte:
754 case Primitive::kPrimChar:
755 case Primitive::kPrimShort:
756 case Primitive::kPrimInt:
757 case Primitive::kPrimNot:
758 locations->SetInAt(0, ArmCoreLocation(R0));
759 break;
760
761 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100762 locations->SetInAt(
763 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100764 break;
765
766 default:
767 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
768 }
769
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000770 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000771}
772
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000773void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100774 if (kIsDebugBuild) {
775 switch (ret->InputAt(0)->GetType()) {
776 case Primitive::kPrimBoolean:
777 case Primitive::kPrimByte:
778 case Primitive::kPrimChar:
779 case Primitive::kPrimShort:
780 case Primitive::kPrimInt:
781 case Primitive::kPrimNot:
782 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
783 break;
784
785 case Primitive::kPrimLong:
786 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
787 break;
788
789 default:
790 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
791 }
792 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000793 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000794}
795
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000796void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100797 codegen_->MarkNotLeaf();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000798 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100799 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100800
801 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100802 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100803 HInstruction* input = invoke->InputAt(i);
804 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
805 }
806
807 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 case Primitive::kPrimBoolean:
809 case Primitive::kPrimByte:
810 case Primitive::kPrimChar:
811 case Primitive::kPrimShort:
812 case Primitive::kPrimInt:
813 case Primitive::kPrimNot:
814 locations->SetOut(ArmCoreLocation(R0));
815 break;
816
817 case Primitive::kPrimLong:
818 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
819 break;
820
821 case Primitive::kPrimVoid:
822 break;
823
824 case Primitive::kPrimDouble:
825 case Primitive::kPrimFloat:
826 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
827 break;
828 }
829
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000830 invoke->SetLocations(locations);
831}
832
833void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100834 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000835}
836
837void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100838 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100839 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
840 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100841 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000842
843 // TODO: Implement all kinds of calls:
844 // 1) boot -> boot
845 // 2) app -> boot
846 // 3) app -> app
847 //
848 // Currently we implement the app -> app logic, which looks up in the resolve cache.
849
850 // temp = method;
851 LoadCurrentMethod(temp);
852 // temp = temp->dex_cache_resolved_methods_;
853 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
854 // temp = temp[index_in_cache]
855 __ ldr(temp, Address(temp, index_in_cache));
856 // LR = temp[offset_of_quick_compiled_code]
857 __ ldr(LR, Address(temp,
858 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
859 // LR()
860 __ blx(LR);
861
862 codegen_->RecordPcInfo(invoke->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100863 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000864}
865
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000866void LocationsBuilderARM::VisitAdd(HAdd* add) {
867 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
868 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100869 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100870 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100871 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100872 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100873 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 break;
875 }
876
877 case Primitive::kPrimBoolean:
878 case Primitive::kPrimByte:
879 case Primitive::kPrimChar:
880 case Primitive::kPrimShort:
881 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
882 break;
883
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000884 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100885 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000886 }
887 add->SetLocations(locations);
888}
889
890void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
891 LocationSummary* locations = add->GetLocations();
892 switch (add->GetResultType()) {
893 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100894 if (locations->InAt(1).IsRegister()) {
895 __ add(locations->Out().AsArm().AsCoreRegister(),
896 locations->InAt(0).AsArm().AsCoreRegister(),
897 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
898 } else {
899 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
900 locations->InAt(0).AsArm().AsCoreRegister(),
901 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
902 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000903 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100904
905 case Primitive::kPrimLong:
906 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
907 locations->InAt(0).AsArm().AsRegisterPairLow(),
908 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
909 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
910 locations->InAt(0).AsArm().AsRegisterPairHigh(),
911 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
912 break;
913
914 case Primitive::kPrimBoolean:
915 case Primitive::kPrimByte:
916 case Primitive::kPrimChar:
917 case Primitive::kPrimShort:
918 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
919 break;
920
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000921 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100922 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000923 }
924}
925
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100926void LocationsBuilderARM::VisitSub(HSub* sub) {
927 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
928 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100929 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100930 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100931 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100932 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100933 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100934 break;
935 }
936
937 case Primitive::kPrimBoolean:
938 case Primitive::kPrimByte:
939 case Primitive::kPrimChar:
940 case Primitive::kPrimShort:
941 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
942 break;
943
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100944 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100945 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100946 }
947 sub->SetLocations(locations);
948}
949
950void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
951 LocationSummary* locations = sub->GetLocations();
952 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100953 case Primitive::kPrimInt: {
954 if (locations->InAt(1).IsRegister()) {
955 __ sub(locations->Out().AsArm().AsCoreRegister(),
956 locations->InAt(0).AsArm().AsCoreRegister(),
957 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
958 } else {
959 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
960 locations->InAt(0).AsArm().AsCoreRegister(),
961 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
962 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100963 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100964 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100965
966 case Primitive::kPrimLong:
967 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
968 locations->InAt(0).AsArm().AsRegisterPairLow(),
969 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
970 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
971 locations->InAt(0).AsArm().AsRegisterPairHigh(),
972 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
973 break;
974
975 case Primitive::kPrimBoolean:
976 case Primitive::kPrimByte:
977 case Primitive::kPrimChar:
978 case Primitive::kPrimShort:
979 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
980 break;
981
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100982 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100983 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100984 }
985}
986
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100987void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100988 codegen_->MarkNotLeaf();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100989 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100990 InvokeRuntimeCallingConvention calling_convention;
991 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
992 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100993 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100994 instruction->SetLocations(locations);
995}
996
997void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
998 InvokeRuntimeCallingConvention calling_convention;
999 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1000 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1001
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001002 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001003 __ ldr(LR, Address(TR, offset));
1004 __ blx(LR);
1005
1006 codegen_->RecordPcInfo(instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001007 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001008}
1009
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001010void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
1011 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001012 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1013 if (location.IsStackSlot()) {
1014 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1015 } else if (location.IsDoubleStackSlot()) {
1016 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001017 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001018 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001019 instruction->SetLocations(locations);
1020}
1021
1022void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001023 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001024}
1025
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001026void LocationsBuilderARM::VisitNot(HNot* instruction) {
1027 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001028 locations->SetInAt(0, Location::RequiresRegister());
1029 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001030 instruction->SetLocations(locations);
1031}
1032
1033void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1034 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001035 __ eor(locations->Out().AsArm().AsCoreRegister(),
1036 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001037}
1038
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001039void LocationsBuilderARM::VisitCompare(HCompare* compare) {
1040 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
1041 locations->SetInAt(0, Location::RequiresRegister());
1042 locations->SetInAt(1, Location::RequiresRegister());
1043 locations->SetOut(Location::RequiresRegister());
1044 compare->SetLocations(locations);
1045}
1046
1047void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1048 Label greater, done;
1049 LocationSummary* locations = compare->GetLocations();
1050 switch (compare->InputAt(0)->GetType()) {
1051 case Primitive::kPrimLong: {
1052 Register output = locations->Out().AsArm().AsCoreRegister();
1053 ArmManagedRegister left = locations->InAt(0).AsArm();
1054 ArmManagedRegister right = locations->InAt(1).AsArm();
1055 Label less, greater, done;
1056 __ cmp(left.AsRegisterPairHigh(),
1057 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1058 __ b(&less, LT);
1059 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001060 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1061 // the status flags.
1062 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001063 __ cmp(left.AsRegisterPairLow(),
1064 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001065 __ b(&done, EQ);
1066 __ b(&less, CC);
1067
1068 __ Bind(&greater);
1069 __ LoadImmediate(output, 1);
1070 __ b(&done);
1071
1072 __ Bind(&less);
1073 __ LoadImmediate(output, -1);
1074
1075 __ Bind(&done);
1076 break;
1077 }
1078 default:
1079 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1080 }
1081}
1082
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001083void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001084 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1085 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1086 locations->SetInAt(i, Location::Any());
1087 }
1088 locations->SetOut(Location::Any());
1089 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001090}
1091
1092void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001093 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001094}
1095
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001096void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1097 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1098 locations->SetInAt(0, Location::RequiresRegister());
1099 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001100 // Temporary registers for the write barrier.
1101 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
1102 locations->AddTemp(Location::RequiresRegister());
1103 locations->AddTemp(Location::RequiresRegister());
1104 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001105 instruction->SetLocations(locations);
1106}
1107
1108void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1109 LocationSummary* locations = instruction->GetLocations();
1110 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1111 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1112 Primitive::Type field_type = instruction->InputAt(1)->GetType();
1113
1114 switch (field_type) {
1115 case Primitive::kPrimBoolean:
1116 case Primitive::kPrimByte: {
1117 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1118 __ StoreToOffset(kStoreByte, value, obj, offset);
1119 break;
1120 }
1121
1122 case Primitive::kPrimShort:
1123 case Primitive::kPrimChar: {
1124 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1125 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1126 break;
1127 }
1128
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001129 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001130 case Primitive::kPrimNot: {
1131 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1132 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001133 if (field_type == Primitive::kPrimNot) {
1134 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1135 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1136 codegen_->MarkGCCard(temp, card, obj, value);
1137 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001138 break;
1139 }
1140
1141 case Primitive::kPrimLong: {
1142 ArmManagedRegister value = locations->InAt(1).AsArm();
1143 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1144 break;
1145 }
1146
1147 case Primitive::kPrimFloat:
1148 case Primitive::kPrimDouble:
1149 LOG(FATAL) << "Unimplemented register type " << field_type;
1150
1151 case Primitive::kPrimVoid:
1152 LOG(FATAL) << "Unreachable type " << field_type;
1153 }
1154}
1155
1156void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1157 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1158 locations->SetInAt(0, Location::RequiresRegister());
1159 locations->SetOut(Location::RequiresRegister());
1160 instruction->SetLocations(locations);
1161}
1162
1163void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1164 LocationSummary* locations = instruction->GetLocations();
1165 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1166 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1167
1168 switch (instruction->GetType()) {
1169 case Primitive::kPrimBoolean: {
1170 Register out = locations->Out().AsArm().AsCoreRegister();
1171 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1172 break;
1173 }
1174
1175 case Primitive::kPrimByte: {
1176 Register out = locations->Out().AsArm().AsCoreRegister();
1177 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1178 break;
1179 }
1180
1181 case Primitive::kPrimShort: {
1182 Register out = locations->Out().AsArm().AsCoreRegister();
1183 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1184 break;
1185 }
1186
1187 case Primitive::kPrimChar: {
1188 Register out = locations->Out().AsArm().AsCoreRegister();
1189 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1190 break;
1191 }
1192
1193 case Primitive::kPrimInt:
1194 case Primitive::kPrimNot: {
1195 Register out = locations->Out().AsArm().AsCoreRegister();
1196 __ LoadFromOffset(kLoadWord, out, obj, offset);
1197 break;
1198 }
1199
1200 case Primitive::kPrimLong: {
1201 // TODO: support volatile.
1202 ArmManagedRegister out = locations->Out().AsArm();
1203 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1204 break;
1205 }
1206
1207 case Primitive::kPrimFloat:
1208 case Primitive::kPrimDouble:
1209 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1210
1211 case Primitive::kPrimVoid:
1212 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1213 }
1214}
1215
1216void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
1217 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1218 locations->SetInAt(0, Location::RequiresRegister());
1219 // TODO: Have a normalization phase that makes this instruction never used.
1220 locations->SetOut(Location::SameAsFirstInput());
1221 instruction->SetLocations(locations);
1222}
1223
1224void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
1225 SlowPathCode* slow_path =
1226 new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
1227 codegen_->AddSlowPath(slow_path);
1228
1229 LocationSummary* locations = instruction->GetLocations();
1230 Location obj = locations->InAt(0);
1231 DCHECK(obj.Equals(locations->Out()));
1232
1233 if (obj.IsRegister()) {
1234 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1235 }
1236 __ b(slow_path->GetEntryLabel(), EQ);
1237}
1238
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001239void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
1240 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1241 locations->SetInAt(0, Location::RequiresRegister());
1242 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1243 locations->SetOut(Location::RequiresRegister());
1244 instruction->SetLocations(locations);
1245}
1246
1247void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1248 LocationSummary* locations = instruction->GetLocations();
1249 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1250 Location index = locations->InAt(1);
1251
1252 switch (instruction->GetType()) {
1253 case Primitive::kPrimBoolean: {
1254 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1255 Register out = locations->Out().AsArm().AsCoreRegister();
1256 if (index.IsConstant()) {
1257 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1258 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1259 } else {
1260 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1261 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1262 }
1263 break;
1264 }
1265
1266 case Primitive::kPrimByte: {
1267 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1268 Register out = locations->Out().AsArm().AsCoreRegister();
1269 if (index.IsConstant()) {
1270 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1271 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1272 } else {
1273 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1274 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1275 }
1276 break;
1277 }
1278
1279 case Primitive::kPrimShort: {
1280 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1281 Register out = locations->Out().AsArm().AsCoreRegister();
1282 if (index.IsConstant()) {
1283 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1284 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1285 } else {
1286 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1287 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1288 }
1289 break;
1290 }
1291
1292 case Primitive::kPrimChar: {
1293 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1294 Register out = locations->Out().AsArm().AsCoreRegister();
1295 if (index.IsConstant()) {
1296 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1297 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1298 } else {
1299 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1300 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1301 }
1302 break;
1303 }
1304
1305 case Primitive::kPrimInt:
1306 case Primitive::kPrimNot: {
1307 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1308 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1309 Register out = locations->Out().AsArm().AsCoreRegister();
1310 if (index.IsConstant()) {
1311 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1312 __ LoadFromOffset(kLoadWord, out, obj, offset);
1313 } else {
1314 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1315 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1316 }
1317 break;
1318 }
1319
1320 case Primitive::kPrimLong: {
1321 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1322 ArmManagedRegister out = locations->Out().AsArm();
1323 if (index.IsConstant()) {
1324 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1325 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1326 } else {
1327 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1328 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1329 }
1330 break;
1331 }
1332
1333 case Primitive::kPrimFloat:
1334 case Primitive::kPrimDouble:
1335 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1336
1337 case Primitive::kPrimVoid:
1338 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1339 }
1340}
1341
1342void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
1343 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1344 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1345 if (value_type == Primitive::kPrimNot) {
1346 InvokeRuntimeCallingConvention calling_convention;
1347 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1348 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1349 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
1350 codegen_->MarkNotLeaf();
1351 } else {
1352 locations->SetInAt(0, Location::RequiresRegister());
1353 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1354 locations->SetInAt(2, Location::RequiresRegister());
1355 }
1356 instruction->SetLocations(locations);
1357}
1358
1359void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1360 LocationSummary* locations = instruction->GetLocations();
1361 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1362 Location index = locations->InAt(1);
1363 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1364
1365 switch (value_type) {
1366 case Primitive::kPrimBoolean:
1367 case Primitive::kPrimByte: {
1368 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1369 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1370 if (index.IsConstant()) {
1371 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1372 __ StoreToOffset(kStoreByte, value, obj, offset);
1373 } else {
1374 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1375 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1376 }
1377 break;
1378 }
1379
1380 case Primitive::kPrimShort:
1381 case Primitive::kPrimChar: {
1382 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1383 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1384 if (index.IsConstant()) {
1385 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1386 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1387 } else {
1388 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1389 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1390 }
1391 break;
1392 }
1393
1394 case Primitive::kPrimInt: {
1395 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1396 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1397 if (index.IsConstant()) {
1398 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1399 __ StoreToOffset(kStoreWord, value, obj, offset);
1400 } else {
1401 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1402 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1403 }
1404 break;
1405 }
1406
1407 case Primitive::kPrimNot: {
1408 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1409 __ ldr(LR, Address(TR, offset));
1410 __ blx(LR);
1411 codegen_->RecordPcInfo(instruction->GetDexPc());
1412 DCHECK(!codegen_->IsLeafMethod());
1413 break;
1414 }
1415
1416 case Primitive::kPrimLong: {
1417 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1418 ArmManagedRegister value = locations->InAt(2).AsArm();
1419 if (index.IsConstant()) {
1420 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1421 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1422 } else {
1423 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1424 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1425 }
1426 break;
1427 }
1428
1429 case Primitive::kPrimFloat:
1430 case Primitive::kPrimDouble:
1431 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1432
1433 case Primitive::kPrimVoid:
1434 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1435 }
1436}
1437
1438void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
1439 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1440 locations->SetInAt(0, Location::RequiresRegister());
1441 locations->SetOut(Location::RequiresRegister());
1442 instruction->SetLocations(locations);
1443}
1444
1445void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1446 LocationSummary* locations = instruction->GetLocations();
1447 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1448 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1449 Register out = locations->Out().AsArm().AsCoreRegister();
1450 __ LoadFromOffset(kLoadWord, out, obj, offset);
1451}
1452
1453void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1454 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1455 locations->SetInAt(0, Location::RequiresRegister());
1456 locations->SetInAt(1, Location::RequiresRegister());
1457 // TODO: Have a normalization phase that makes this instruction never used.
1458 locations->SetOut(Location::SameAsFirstInput());
1459 instruction->SetLocations(locations);
1460}
1461
1462void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1463 LocationSummary* locations = instruction->GetLocations();
1464 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
1465 instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1466 codegen_->AddSlowPath(slow_path);
1467
1468 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1469 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1470
1471 __ cmp(index, ShifterOperand(length));
1472 __ b(slow_path->GetEntryLabel(), CS);
1473}
1474
1475void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1476 Label is_null;
1477 __ CompareAndBranchIfZero(value, &is_null);
1478 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1479 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1480 __ strb(card, Address(card, temp));
1481 __ Bind(&is_null);
1482}
1483
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001484void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1485 temp->SetLocations(nullptr);
1486}
1487
1488void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1489 // Nothing to do, this is driven by the code generator.
1490}
1491
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001492void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001493 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001494}
1495
1496void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001497 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1498}
1499
1500ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1501 return codegen_->GetAssembler();
1502}
1503
1504void ParallelMoveResolverARM::EmitMove(size_t index) {
1505 MoveOperands* move = moves_.Get(index);
1506 Location source = move->GetSource();
1507 Location destination = move->GetDestination();
1508
1509 if (source.IsRegister()) {
1510 if (destination.IsRegister()) {
1511 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1512 } else {
1513 DCHECK(destination.IsStackSlot());
1514 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1515 SP, destination.GetStackIndex());
1516 }
1517 } else if (source.IsStackSlot()) {
1518 if (destination.IsRegister()) {
1519 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1520 SP, source.GetStackIndex());
1521 } else {
1522 DCHECK(destination.IsStackSlot());
1523 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1524 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1525 }
1526 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001527 DCHECK(source.IsConstant());
1528 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1529 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1530 if (destination.IsRegister()) {
1531 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1532 } else {
1533 DCHECK(destination.IsStackSlot());
1534 __ LoadImmediate(IP, value);
1535 __ str(IP, Address(SP, destination.GetStackIndex()));
1536 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001537 }
1538}
1539
1540void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1541 __ Mov(IP, reg);
1542 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1543 __ StoreToOffset(kStoreWord, IP, SP, mem);
1544}
1545
1546void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1547 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1548 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1549 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1550 SP, mem1 + stack_offset);
1551 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1552 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1553 SP, mem2 + stack_offset);
1554 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1555}
1556
1557void ParallelMoveResolverARM::EmitSwap(size_t index) {
1558 MoveOperands* move = moves_.Get(index);
1559 Location source = move->GetSource();
1560 Location destination = move->GetDestination();
1561
1562 if (source.IsRegister() && destination.IsRegister()) {
1563 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1564 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1565 __ Mov(IP, source.AsArm().AsCoreRegister());
1566 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1567 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1568 } else if (source.IsRegister() && destination.IsStackSlot()) {
1569 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1570 } else if (source.IsStackSlot() && destination.IsRegister()) {
1571 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1572 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1573 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1574 } else {
1575 LOG(FATAL) << "Unimplemented";
1576 }
1577}
1578
1579void ParallelMoveResolverARM::SpillScratch(int reg) {
1580 __ Push(static_cast<Register>(reg));
1581}
1582
1583void ParallelMoveResolverARM::RestoreScratch(int reg) {
1584 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001585}
1586
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001587} // namespace arm
1588} // namespace art