blob: e72e39ba71eae75209e03fbb67b07d80ff48da56 [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 Geoffray3c7bb982014-07-23 16:04:16 +010093class BoundsCheckSlowPathARM : public SlowPathCode {
94 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010095 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction,
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010096 Location index_location,
97 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +010098 : instruction_(instruction),
99 index_location_(index_location),
100 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100101
102 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
103 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
104 __ Bind(GetEntryLabel());
105 InvokeRuntimeCallingConvention calling_convention;
106 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
107 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
108 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
109 __ ldr(LR, Address(TR, offset));
110 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100111 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100112 }
113
114 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100115 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100116 const Location index_location_;
117 const Location length_location_;
118
119 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
120};
121
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100122#undef __
123#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700124
125inline Condition ARMCondition(IfCondition cond) {
126 switch (cond) {
127 case kCondEQ: return EQ;
128 case kCondNE: return NE;
129 case kCondLT: return LT;
130 case kCondLE: return LE;
131 case kCondGT: return GT;
132 case kCondGE: return GE;
133 default:
134 LOG(FATAL) << "Unknown if condition";
135 }
136 return EQ; // Unreachable.
137}
138
139inline Condition ARMOppositeCondition(IfCondition cond) {
140 switch (cond) {
141 case kCondEQ: return NE;
142 case kCondNE: return EQ;
143 case kCondLT: return GE;
144 case kCondLE: return GT;
145 case kCondGT: return LE;
146 case kCondGE: return LT;
147 default:
148 LOG(FATAL) << "Unknown if condition";
149 }
150 return EQ; // Unreachable.
151}
152
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100153void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
154 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
155}
156
157void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
158 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
159}
160
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100161CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
162 : CodeGenerator(graph, kNumberOfRegIds),
163 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100164 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100165 move_resolver_(graph->GetArena(), this),
166 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100167
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100168size_t CodeGeneratorARM::FrameEntrySpillSize() const {
169 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
170}
171
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100172static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
173 return blocked_registers + kNumberOfAllocIds;
174}
175
176ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
177 bool* blocked_registers) const {
178 switch (type) {
179 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100180 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
181 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100182 ArmManagedRegister pair =
183 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
184 blocked_registers[pair.AsRegisterPairLow()] = true;
185 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100186 // Block all other register pairs that share a register with `pair`.
187 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
188 ArmManagedRegister current =
189 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
190 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
191 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
192 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
193 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
194 blocked_register_pairs[i] = true;
195 }
196 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100197 return pair;
198 }
199
200 case Primitive::kPrimByte:
201 case Primitive::kPrimBoolean:
202 case Primitive::kPrimChar:
203 case Primitive::kPrimShort:
204 case Primitive::kPrimInt:
205 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100206 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
207 // Block all register pairs that contain `reg`.
208 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
209 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
210 ArmManagedRegister current =
211 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
212 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
213 blocked_register_pairs[i] = true;
214 }
215 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100216 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
217 }
218
219 case Primitive::kPrimFloat:
220 case Primitive::kPrimDouble:
221 LOG(FATAL) << "Unimplemented register type " << type;
222
223 case Primitive::kPrimVoid:
224 LOG(FATAL) << "Unreachable type " << type;
225 }
226
227 return ManagedRegister::NoRegister();
228}
229
230void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
231 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
232
233 // Don't allocate the dalvik style register pair passing.
234 blocked_register_pairs[R1_R2] = true;
235
236 // Stack register, LR and PC are always reserved.
237 blocked_registers[SP] = true;
238 blocked_registers[LR] = true;
239 blocked_registers[PC] = true;
240
241 // Reserve R4 for suspend check.
242 blocked_registers[R4] = true;
243 blocked_register_pairs[R4_R5] = true;
244
245 // Reserve thread register.
246 blocked_registers[TR] = true;
247
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100248 // Reserve temp register.
249 blocked_registers[IP] = true;
250
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100251 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100252 // We always save and restore R6 and R7 to make sure we can use three
253 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100254 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100255 blocked_registers[R8] = true;
256 blocked_registers[R10] = true;
257 blocked_registers[R11] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100258}
259
260size_t CodeGeneratorARM::GetNumberOfRegisters() const {
261 return kNumberOfRegIds;
262}
263
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100264InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
265 : HGraphVisitor(graph),
266 assembler_(codegen->GetAssembler()),
267 codegen_(codegen) {}
268
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000269void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700270 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100271 if (!skip_overflow_check) {
272 if (kExplicitStackOverflowCheck) {
273 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
274 AddSlowPath(slow_path);
275
276 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
277 __ cmp(SP, ShifterOperand(IP));
278 __ b(slow_path->GetEntryLabel(), CC);
279 } else {
280 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
281 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100282 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100283 }
284 }
285
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100286 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
287 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000288
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100289 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100290 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000291 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000292}
293
294void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100295 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100296 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000297}
298
299void CodeGeneratorARM::Bind(Label* label) {
300 __ Bind(label);
301}
302
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100303Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
304 switch (load->GetType()) {
305 case Primitive::kPrimLong:
306 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
307 break;
308
309 case Primitive::kPrimInt:
310 case Primitive::kPrimNot:
311 return Location::StackSlot(GetStackSlot(load->GetLocal()));
312
313 case Primitive::kPrimFloat:
314 case Primitive::kPrimDouble:
315 LOG(FATAL) << "Unimplemented type " << load->GetType();
316
317 case Primitive::kPrimBoolean:
318 case Primitive::kPrimByte:
319 case Primitive::kPrimChar:
320 case Primitive::kPrimShort:
321 case Primitive::kPrimVoid:
322 LOG(FATAL) << "Unexpected type " << load->GetType();
323 }
324
325 LOG(FATAL) << "Unreachable";
326 return Location();
327}
328
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100329Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
330 switch (type) {
331 case Primitive::kPrimBoolean:
332 case Primitive::kPrimByte:
333 case Primitive::kPrimChar:
334 case Primitive::kPrimShort:
335 case Primitive::kPrimInt:
336 case Primitive::kPrimNot: {
337 uint32_t index = gp_index_++;
338 if (index < calling_convention.GetNumberOfRegisters()) {
339 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
340 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100341 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100342 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100343 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100344
345 case Primitive::kPrimLong: {
346 uint32_t index = gp_index_;
347 gp_index_ += 2;
348 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
349 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
350 calling_convention.GetRegisterPairAt(index)));
351 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
352 return Location::QuickParameter(index);
353 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100354 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100355 }
356 }
357
358 case Primitive::kPrimDouble:
359 case Primitive::kPrimFloat:
360 LOG(FATAL) << "Unimplemented parameter type " << type;
361 break;
362
363 case Primitive::kPrimVoid:
364 LOG(FATAL) << "Unexpected parameter type " << type;
365 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100366 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100367 return Location();
368}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100369
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100370void CodeGeneratorARM::Move32(Location destination, Location source) {
371 if (source.Equals(destination)) {
372 return;
373 }
374 if (destination.IsRegister()) {
375 if (source.IsRegister()) {
376 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
377 } else {
378 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
379 }
380 } else {
381 DCHECK(destination.IsStackSlot());
382 if (source.IsRegister()) {
383 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
384 } else {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100385 __ ldr(IP, Address(SP, source.GetStackIndex()));
386 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100387 }
388 }
389}
390
391void CodeGeneratorARM::Move64(Location destination, Location source) {
392 if (source.Equals(destination)) {
393 return;
394 }
395 if (destination.IsRegister()) {
396 if (source.IsRegister()) {
397 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
398 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
399 } else if (source.IsQuickParameter()) {
400 uint32_t argument_index = source.GetQuickParameterIndex();
401 InvokeDexCallingConvention calling_convention;
402 __ Mov(destination.AsArm().AsRegisterPairLow(),
403 calling_convention.GetRegisterAt(argument_index));
404 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100405 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100406 } else {
407 DCHECK(source.IsDoubleStackSlot());
408 if (destination.AsArm().AsRegisterPair() == R1_R2) {
409 __ ldr(R1, Address(SP, source.GetStackIndex()));
410 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
411 } else {
412 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
413 SP, source.GetStackIndex());
414 }
415 }
416 } else if (destination.IsQuickParameter()) {
417 InvokeDexCallingConvention calling_convention;
418 uint32_t argument_index = destination.GetQuickParameterIndex();
419 if (source.IsRegister()) {
420 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
421 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100422 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100423 } else {
424 DCHECK(source.IsDoubleStackSlot());
425 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100426 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
427 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100428 }
429 } else {
430 DCHECK(destination.IsDoubleStackSlot());
431 if (source.IsRegister()) {
432 if (source.AsArm().AsRegisterPair() == R1_R2) {
433 __ str(R1, Address(SP, destination.GetStackIndex()));
434 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
435 } else {
436 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
437 SP, destination.GetStackIndex());
438 }
439 } else if (source.IsQuickParameter()) {
440 InvokeDexCallingConvention calling_convention;
441 uint32_t argument_index = source.GetQuickParameterIndex();
442 __ str(calling_convention.GetRegisterAt(argument_index),
443 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100444 __ ldr(R0,
445 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
446 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100447 } else {
448 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100449 __ ldr(IP, Address(SP, source.GetStackIndex()));
450 __ str(IP, Address(SP, destination.GetStackIndex()));
451 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
452 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100453 }
454 }
455}
456
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100457void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100458 LocationSummary* locations = instruction->GetLocations();
459 if (locations != nullptr && locations->Out().Equals(location)) {
460 return;
461 }
462
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100463 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100464 int32_t value = instruction->AsIntConstant()->GetValue();
465 if (location.IsRegister()) {
466 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
467 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100468 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100469 __ LoadImmediate(IP, value);
470 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100471 }
472 } else if (instruction->AsLongConstant() != nullptr) {
473 int64_t value = instruction->AsLongConstant()->GetValue();
474 if (location.IsRegister()) {
475 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
476 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
477 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100478 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100479 __ LoadImmediate(IP, Low32Bits(value));
480 __ str(IP, Address(SP, location.GetStackIndex()));
481 __ LoadImmediate(IP, High32Bits(value));
482 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100483 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100484 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100485 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
486 switch (instruction->GetType()) {
487 case Primitive::kPrimBoolean:
488 case Primitive::kPrimByte:
489 case Primitive::kPrimChar:
490 case Primitive::kPrimShort:
491 case Primitive::kPrimInt:
492 case Primitive::kPrimNot:
493 Move32(location, Location::StackSlot(stack_slot));
494 break;
495
496 case Primitive::kPrimLong:
497 Move64(location, Location::DoubleStackSlot(stack_slot));
498 break;
499
500 default:
501 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
502 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000503 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100504 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100505 switch (instruction->GetType()) {
506 case Primitive::kPrimBoolean:
507 case Primitive::kPrimByte:
508 case Primitive::kPrimChar:
509 case Primitive::kPrimShort:
510 case Primitive::kPrimNot:
511 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100512 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100513 break;
514
515 case Primitive::kPrimLong:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100516 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100517 break;
518
519 default:
520 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
521 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000522 }
523}
524
525void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000526 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000527}
528
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000529void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000530 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000531 if (GetGraph()->GetExitBlock() == successor) {
532 codegen_->GenerateFrameExit();
533 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
534 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000535 }
536}
537
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000538void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000539 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000540}
541
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000542void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000543 if (kIsDebugBuild) {
544 __ Comment("Unreachable");
545 __ bkpt(0);
546 }
547}
548
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000549void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100550 LocationSummary* locations =
551 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100552 HInstruction* cond = if_instr->InputAt(0);
553 DCHECK(cond->IsCondition());
554 HCondition* condition = cond->AsCondition();
555 if (condition->NeedsMaterialization()) {
556 locations->SetInAt(0, Location::Any());
557 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000558}
559
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000560void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700561 HInstruction* cond = if_instr->InputAt(0);
562 DCHECK(cond->IsCondition());
563 HCondition* condition = cond->AsCondition();
564 if (condition->NeedsMaterialization()) {
565 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100566 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700567 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
568 ShifterOperand(0));
569 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
570 } else {
571 // Condition has not been materialized, use its inputs as the comparison and its
572 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100573 LocationSummary* locations = condition->GetLocations();
574 if (locations->InAt(1).IsRegister()) {
575 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
576 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
577 } else {
578 DCHECK(locations->InAt(1).IsConstant());
579 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
580 ShifterOperand operand;
581 if (ShifterOperand::CanHoldArm(value, &operand)) {
582 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
583 } else {
584 Register temp = IP;
585 __ LoadImmediate(temp, value);
586 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
587 }
588 }
Dave Allison20dfc792014-06-16 20:44:29 -0700589 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
590 ARMCondition(condition->GetCondition()));
591 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100592
Dave Allison20dfc792014-06-16 20:44:29 -0700593 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
594 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000595 }
596}
597
Dave Allison20dfc792014-06-16 20:44:29 -0700598
599void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100600 LocationSummary* locations =
601 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100602 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100603 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100604 if (comp->NeedsMaterialization()) {
605 locations->SetOut(Location::RequiresRegister());
606 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000607}
608
Dave Allison20dfc792014-06-16 20:44:29 -0700609void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100610 if (!comp->NeedsMaterialization()) return;
611
612 LocationSummary* locations = comp->GetLocations();
613 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700614 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
615 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100616 } else {
617 DCHECK(locations->InAt(1).IsConstant());
618 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
619 ShifterOperand operand;
620 if (ShifterOperand::CanHoldArm(value, &operand)) {
621 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
622 } else {
623 Register temp = IP;
624 __ LoadImmediate(temp, value);
625 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
626 }
Dave Allison20dfc792014-06-16 20:44:29 -0700627 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100628 __ it(ARMCondition(comp->GetCondition()), kItElse);
629 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
630 ARMCondition(comp->GetCondition()));
631 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
632 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700633}
634
635void LocationsBuilderARM::VisitEqual(HEqual* comp) {
636 VisitCondition(comp);
637}
638
639void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
640 VisitCondition(comp);
641}
642
643void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
644 VisitCondition(comp);
645}
646
647void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
648 VisitCondition(comp);
649}
650
651void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
652 VisitCondition(comp);
653}
654
655void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
656 VisitCondition(comp);
657}
658
659void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
660 VisitCondition(comp);
661}
662
663void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
664 VisitCondition(comp);
665}
666
667void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
668 VisitCondition(comp);
669}
670
671void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
672 VisitCondition(comp);
673}
674
675void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
676 VisitCondition(comp);
677}
678
679void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
680 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000681}
682
683void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000684 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000685}
686
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000687void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
688 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000689}
690
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000691void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100692 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000693}
694
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000695void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100696 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000697}
698
699void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100700 LocationSummary* locations =
701 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100702 switch (store->InputAt(1)->GetType()) {
703 case Primitive::kPrimBoolean:
704 case Primitive::kPrimByte:
705 case Primitive::kPrimChar:
706 case Primitive::kPrimShort:
707 case Primitive::kPrimInt:
708 case Primitive::kPrimNot:
709 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
710 break;
711
712 case Primitive::kPrimLong:
713 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
714 break;
715
716 default:
717 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
718 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000719}
720
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000721void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000722}
723
724void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100725 LocationSummary* locations =
726 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100727 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000728}
729
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000730void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000731}
732
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100733void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100734 LocationSummary* locations =
735 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100736 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100737}
738
739void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
740 // Will be generated at use site.
741}
742
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000743void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000744 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000745}
746
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000747void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
748 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000749}
750
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000751void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100752 LocationSummary* locations =
753 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100754 switch (ret->InputAt(0)->GetType()) {
755 case Primitive::kPrimBoolean:
756 case Primitive::kPrimByte:
757 case Primitive::kPrimChar:
758 case Primitive::kPrimShort:
759 case Primitive::kPrimInt:
760 case Primitive::kPrimNot:
761 locations->SetInAt(0, ArmCoreLocation(R0));
762 break;
763
764 case Primitive::kPrimLong:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100765 locations->SetInAt(
766 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100767 break;
768
769 default:
770 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
771 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000772}
773
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000774void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100775 if (kIsDebugBuild) {
776 switch (ret->InputAt(0)->GetType()) {
777 case Primitive::kPrimBoolean:
778 case Primitive::kPrimByte:
779 case Primitive::kPrimChar:
780 case Primitive::kPrimShort:
781 case Primitive::kPrimInt:
782 case Primitive::kPrimNot:
783 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
784 break;
785
786 case Primitive::kPrimLong:
787 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
788 break;
789
790 default:
791 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
792 }
793 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000794 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000795}
796
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000797void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100798 LocationSummary* locations =
799 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100800 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100801
802 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100803 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100804 HInstruction* input = invoke->InputAt(i);
805 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
806 }
807
808 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 case Primitive::kPrimBoolean:
810 case Primitive::kPrimByte:
811 case Primitive::kPrimChar:
812 case Primitive::kPrimShort:
813 case Primitive::kPrimInt:
814 case Primitive::kPrimNot:
815 locations->SetOut(ArmCoreLocation(R0));
816 break;
817
818 case Primitive::kPrimLong:
819 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
820 break;
821
822 case Primitive::kPrimVoid:
823 break;
824
825 case Primitive::kPrimDouble:
826 case Primitive::kPrimFloat:
827 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
828 break;
829 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000830}
831
832void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100833 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000834}
835
836void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100837 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100838 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
839 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100840 invoke->GetIndexInDexCache() * kArmWordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000841
842 // TODO: Implement all kinds of calls:
843 // 1) boot -> boot
844 // 2) app -> boot
845 // 3) app -> app
846 //
847 // Currently we implement the app -> app logic, which looks up in the resolve cache.
848
849 // temp = method;
850 LoadCurrentMethod(temp);
851 // temp = temp->dex_cache_resolved_methods_;
852 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
853 // temp = temp[index_in_cache]
854 __ ldr(temp, Address(temp, index_in_cache));
855 // LR = temp[offset_of_quick_compiled_code]
856 __ ldr(LR, Address(temp,
857 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
858 // LR()
859 __ blx(LR);
860
Nicolas Geoffray39468442014-09-02 15:17:15 +0100861 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100862 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000863}
864
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000865void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100866 LocationSummary* locations =
867 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000868 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 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000887}
888
889void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
890 LocationSummary* locations = add->GetLocations();
891 switch (add->GetResultType()) {
892 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100893 if (locations->InAt(1).IsRegister()) {
894 __ add(locations->Out().AsArm().AsCoreRegister(),
895 locations->InAt(0).AsArm().AsCoreRegister(),
896 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
897 } else {
898 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
899 locations->InAt(0).AsArm().AsCoreRegister(),
900 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
901 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000902 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100903
904 case Primitive::kPrimLong:
905 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
906 locations->InAt(0).AsArm().AsRegisterPairLow(),
907 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
908 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
909 locations->InAt(0).AsArm().AsRegisterPairHigh(),
910 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
911 break;
912
913 case Primitive::kPrimBoolean:
914 case Primitive::kPrimByte:
915 case Primitive::kPrimChar:
916 case Primitive::kPrimShort:
917 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
918 break;
919
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000920 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100921 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000922 }
923}
924
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100925void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100926 LocationSummary* locations =
927 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100928 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 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100947}
948
949void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
950 LocationSummary* locations = sub->GetLocations();
951 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100952 case Primitive::kPrimInt: {
953 if (locations->InAt(1).IsRegister()) {
954 __ sub(locations->Out().AsArm().AsCoreRegister(),
955 locations->InAt(0).AsArm().AsCoreRegister(),
956 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
957 } else {
958 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
959 locations->InAt(0).AsArm().AsCoreRegister(),
960 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
961 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100962 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100963 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100964
965 case Primitive::kPrimLong:
966 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
967 locations->InAt(0).AsArm().AsRegisterPairLow(),
968 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
969 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
970 locations->InAt(0).AsArm().AsRegisterPairHigh(),
971 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
972 break;
973
974 case Primitive::kPrimBoolean:
975 case Primitive::kPrimByte:
976 case Primitive::kPrimChar:
977 case Primitive::kPrimShort:
978 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
979 break;
980
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100981 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100982 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100983 }
984}
985
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100986void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100987 LocationSummary* locations =
988 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100989 InvokeRuntimeCallingConvention calling_convention;
990 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
991 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100992 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100993}
994
995void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
996 InvokeRuntimeCallingConvention calling_convention;
997 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
998 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
999
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001000 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001001 __ ldr(LR, Address(TR, offset));
1002 __ blx(LR);
1003
Nicolas Geoffray39468442014-09-02 15:17:15 +01001004 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001005 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001006}
1007
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001008void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001009 LocationSummary* locations =
1010 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001011 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1012 if (location.IsStackSlot()) {
1013 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1014 } else if (location.IsDoubleStackSlot()) {
1015 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001016 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001017 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001018}
1019
1020void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001021 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001022}
1023
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001024void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001025 LocationSummary* locations =
1026 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001027 locations->SetInAt(0, Location::RequiresRegister());
1028 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001029}
1030
1031void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1032 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001033 __ eor(locations->Out().AsArm().AsCoreRegister(),
1034 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001035}
1036
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001037void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001038 LocationSummary* locations =
1039 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001040 locations->SetInAt(0, Location::RequiresRegister());
1041 locations->SetInAt(1, Location::RequiresRegister());
1042 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001043}
1044
1045void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1046 Label greater, done;
1047 LocationSummary* locations = compare->GetLocations();
1048 switch (compare->InputAt(0)->GetType()) {
1049 case Primitive::kPrimLong: {
1050 Register output = locations->Out().AsArm().AsCoreRegister();
1051 ArmManagedRegister left = locations->InAt(0).AsArm();
1052 ArmManagedRegister right = locations->InAt(1).AsArm();
1053 Label less, greater, done;
1054 __ cmp(left.AsRegisterPairHigh(),
1055 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1056 __ b(&less, LT);
1057 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001058 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1059 // the status flags.
1060 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001061 __ cmp(left.AsRegisterPairLow(),
1062 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001063 __ b(&done, EQ);
1064 __ b(&less, CC);
1065
1066 __ Bind(&greater);
1067 __ LoadImmediate(output, 1);
1068 __ b(&done);
1069
1070 __ Bind(&less);
1071 __ LoadImmediate(output, -1);
1072
1073 __ Bind(&done);
1074 break;
1075 }
1076 default:
1077 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1078 }
1079}
1080
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001081void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001082 LocationSummary* locations =
1083 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001084 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1085 locations->SetInAt(i, Location::Any());
1086 }
1087 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001088}
1089
1090void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001091 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001092}
1093
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001094void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001095 LocationSummary* locations =
1096 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001097 locations->SetInAt(0, Location::RequiresRegister());
1098 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001099 // Temporary registers for the write barrier.
Nicolas Geoffray39468442014-09-02 15:17:15 +01001100 if (instruction->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001101 locations->AddTemp(Location::RequiresRegister());
1102 locations->AddTemp(Location::RequiresRegister());
1103 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001104}
1105
1106void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1107 LocationSummary* locations = instruction->GetLocations();
1108 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1109 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001110 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001111
1112 switch (field_type) {
1113 case Primitive::kPrimBoolean:
1114 case Primitive::kPrimByte: {
1115 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1116 __ StoreToOffset(kStoreByte, value, obj, offset);
1117 break;
1118 }
1119
1120 case Primitive::kPrimShort:
1121 case Primitive::kPrimChar: {
1122 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1123 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1124 break;
1125 }
1126
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001127 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001128 case Primitive::kPrimNot: {
1129 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1130 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001131 if (field_type == Primitive::kPrimNot) {
1132 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1133 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1134 codegen_->MarkGCCard(temp, card, obj, value);
1135 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001136 break;
1137 }
1138
1139 case Primitive::kPrimLong: {
1140 ArmManagedRegister value = locations->InAt(1).AsArm();
1141 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1142 break;
1143 }
1144
1145 case Primitive::kPrimFloat:
1146 case Primitive::kPrimDouble:
1147 LOG(FATAL) << "Unimplemented register type " << field_type;
1148
1149 case Primitive::kPrimVoid:
1150 LOG(FATAL) << "Unreachable type " << field_type;
1151 }
1152}
1153
1154void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001155 LocationSummary* locations =
1156 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001157 locations->SetInAt(0, Location::RequiresRegister());
1158 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001159}
1160
1161void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1162 LocationSummary* locations = instruction->GetLocations();
1163 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1164 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1165
1166 switch (instruction->GetType()) {
1167 case Primitive::kPrimBoolean: {
1168 Register out = locations->Out().AsArm().AsCoreRegister();
1169 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1170 break;
1171 }
1172
1173 case Primitive::kPrimByte: {
1174 Register out = locations->Out().AsArm().AsCoreRegister();
1175 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1176 break;
1177 }
1178
1179 case Primitive::kPrimShort: {
1180 Register out = locations->Out().AsArm().AsCoreRegister();
1181 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1182 break;
1183 }
1184
1185 case Primitive::kPrimChar: {
1186 Register out = locations->Out().AsArm().AsCoreRegister();
1187 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1188 break;
1189 }
1190
1191 case Primitive::kPrimInt:
1192 case Primitive::kPrimNot: {
1193 Register out = locations->Out().AsArm().AsCoreRegister();
1194 __ LoadFromOffset(kLoadWord, out, obj, offset);
1195 break;
1196 }
1197
1198 case Primitive::kPrimLong: {
1199 // TODO: support volatile.
1200 ArmManagedRegister out = locations->Out().AsArm();
1201 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1202 break;
1203 }
1204
1205 case Primitive::kPrimFloat:
1206 case Primitive::kPrimDouble:
1207 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1208
1209 case Primitive::kPrimVoid:
1210 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1211 }
1212}
1213
1214void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001215 LocationSummary* locations =
1216 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001217 locations->SetInAt(0, Location::RequiresRegister());
1218 // TODO: Have a normalization phase that makes this instruction never used.
1219 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001220}
1221
1222void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001223 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001224 codegen_->AddSlowPath(slow_path);
1225
1226 LocationSummary* locations = instruction->GetLocations();
1227 Location obj = locations->InAt(0);
1228 DCHECK(obj.Equals(locations->Out()));
1229
1230 if (obj.IsRegister()) {
1231 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
1232 }
1233 __ b(slow_path->GetEntryLabel(), EQ);
1234}
1235
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001236void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001237 LocationSummary* locations =
1238 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001239 locations->SetInAt(0, Location::RequiresRegister());
1240 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1241 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001242}
1243
1244void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1245 LocationSummary* locations = instruction->GetLocations();
1246 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1247 Location index = locations->InAt(1);
1248
1249 switch (instruction->GetType()) {
1250 case Primitive::kPrimBoolean: {
1251 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1252 Register out = locations->Out().AsArm().AsCoreRegister();
1253 if (index.IsConstant()) {
1254 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1255 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1256 } else {
1257 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1258 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1259 }
1260 break;
1261 }
1262
1263 case Primitive::kPrimByte: {
1264 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1265 Register out = locations->Out().AsArm().AsCoreRegister();
1266 if (index.IsConstant()) {
1267 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1268 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1269 } else {
1270 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1271 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1272 }
1273 break;
1274 }
1275
1276 case Primitive::kPrimShort: {
1277 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1278 Register out = locations->Out().AsArm().AsCoreRegister();
1279 if (index.IsConstant()) {
1280 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1281 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1282 } else {
1283 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1284 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1285 }
1286 break;
1287 }
1288
1289 case Primitive::kPrimChar: {
1290 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1291 Register out = locations->Out().AsArm().AsCoreRegister();
1292 if (index.IsConstant()) {
1293 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1294 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1295 } else {
1296 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1297 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1298 }
1299 break;
1300 }
1301
1302 case Primitive::kPrimInt:
1303 case Primitive::kPrimNot: {
1304 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1305 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1306 Register out = locations->Out().AsArm().AsCoreRegister();
1307 if (index.IsConstant()) {
1308 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1309 __ LoadFromOffset(kLoadWord, out, obj, offset);
1310 } else {
1311 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1312 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1313 }
1314 break;
1315 }
1316
1317 case Primitive::kPrimLong: {
1318 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1319 ArmManagedRegister out = locations->Out().AsArm();
1320 if (index.IsConstant()) {
1321 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1322 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1323 } else {
1324 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1325 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1326 }
1327 break;
1328 }
1329
1330 case Primitive::kPrimFloat:
1331 case Primitive::kPrimDouble:
1332 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1333
1334 case Primitive::kPrimVoid:
1335 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1336 }
1337}
1338
1339void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001340 Primitive::Type value_type = instruction->GetComponentType();
1341 bool is_object = value_type == Primitive::kPrimNot;
1342 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1343 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1344 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001345 InvokeRuntimeCallingConvention calling_convention;
1346 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1347 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1348 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001349 } else {
1350 locations->SetInAt(0, Location::RequiresRegister());
1351 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1352 locations->SetInAt(2, Location::RequiresRegister());
1353 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001354}
1355
1356void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1357 LocationSummary* locations = instruction->GetLocations();
1358 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1359 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001360 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001361
1362 switch (value_type) {
1363 case Primitive::kPrimBoolean:
1364 case Primitive::kPrimByte: {
1365 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1366 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1367 if (index.IsConstant()) {
1368 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1369 __ StoreToOffset(kStoreByte, value, obj, offset);
1370 } else {
1371 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1372 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1373 }
1374 break;
1375 }
1376
1377 case Primitive::kPrimShort:
1378 case Primitive::kPrimChar: {
1379 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1380 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1381 if (index.IsConstant()) {
1382 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1383 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1384 } else {
1385 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1386 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1387 }
1388 break;
1389 }
1390
1391 case Primitive::kPrimInt: {
1392 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1393 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1394 if (index.IsConstant()) {
1395 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1396 __ StoreToOffset(kStoreWord, value, obj, offset);
1397 } else {
1398 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1399 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1400 }
1401 break;
1402 }
1403
1404 case Primitive::kPrimNot: {
1405 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1406 __ ldr(LR, Address(TR, offset));
1407 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001408 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001409 DCHECK(!codegen_->IsLeafMethod());
1410 break;
1411 }
1412
1413 case Primitive::kPrimLong: {
1414 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1415 ArmManagedRegister value = locations->InAt(2).AsArm();
1416 if (index.IsConstant()) {
1417 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1418 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1419 } else {
1420 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1421 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1422 }
1423 break;
1424 }
1425
1426 case Primitive::kPrimFloat:
1427 case Primitive::kPrimDouble:
1428 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1429
1430 case Primitive::kPrimVoid:
1431 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1432 }
1433}
1434
1435void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001436 LocationSummary* locations =
1437 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001438 locations->SetInAt(0, Location::RequiresRegister());
1439 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001440}
1441
1442void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1443 LocationSummary* locations = instruction->GetLocations();
1444 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1445 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1446 Register out = locations->Out().AsArm().AsCoreRegister();
1447 __ LoadFromOffset(kLoadWord, out, obj, offset);
1448}
1449
1450void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001451 LocationSummary* locations =
1452 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001453 locations->SetInAt(0, Location::RequiresRegister());
1454 locations->SetInAt(1, Location::RequiresRegister());
1455 // TODO: Have a normalization phase that makes this instruction never used.
1456 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001457}
1458
1459void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1460 LocationSummary* locations = instruction->GetLocations();
1461 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001462 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001463 codegen_->AddSlowPath(slow_path);
1464
1465 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1466 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1467
1468 __ cmp(index, ShifterOperand(length));
1469 __ b(slow_path->GetEntryLabel(), CS);
1470}
1471
1472void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1473 Label is_null;
1474 __ CompareAndBranchIfZero(value, &is_null);
1475 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1476 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1477 __ strb(card, Address(card, temp));
1478 __ Bind(&is_null);
1479}
1480
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001481void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1482 temp->SetLocations(nullptr);
1483}
1484
1485void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1486 // Nothing to do, this is driven by the code generator.
1487}
1488
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001489void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001490 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001491}
1492
1493void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001494 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1495}
1496
1497ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1498 return codegen_->GetAssembler();
1499}
1500
1501void ParallelMoveResolverARM::EmitMove(size_t index) {
1502 MoveOperands* move = moves_.Get(index);
1503 Location source = move->GetSource();
1504 Location destination = move->GetDestination();
1505
1506 if (source.IsRegister()) {
1507 if (destination.IsRegister()) {
1508 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1509 } else {
1510 DCHECK(destination.IsStackSlot());
1511 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1512 SP, destination.GetStackIndex());
1513 }
1514 } else if (source.IsStackSlot()) {
1515 if (destination.IsRegister()) {
1516 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1517 SP, source.GetStackIndex());
1518 } else {
1519 DCHECK(destination.IsStackSlot());
1520 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1521 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1522 }
1523 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001524 DCHECK(source.IsConstant());
1525 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1526 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1527 if (destination.IsRegister()) {
1528 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1529 } else {
1530 DCHECK(destination.IsStackSlot());
1531 __ LoadImmediate(IP, value);
1532 __ str(IP, Address(SP, destination.GetStackIndex()));
1533 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001534 }
1535}
1536
1537void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1538 __ Mov(IP, reg);
1539 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1540 __ StoreToOffset(kStoreWord, IP, SP, mem);
1541}
1542
1543void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1544 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1545 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1546 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1547 SP, mem1 + stack_offset);
1548 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1549 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1550 SP, mem2 + stack_offset);
1551 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1552}
1553
1554void ParallelMoveResolverARM::EmitSwap(size_t index) {
1555 MoveOperands* move = moves_.Get(index);
1556 Location source = move->GetSource();
1557 Location destination = move->GetDestination();
1558
1559 if (source.IsRegister() && destination.IsRegister()) {
1560 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1561 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1562 __ Mov(IP, source.AsArm().AsCoreRegister());
1563 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1564 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1565 } else if (source.IsRegister() && destination.IsStackSlot()) {
1566 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1567 } else if (source.IsStackSlot() && destination.IsRegister()) {
1568 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1569 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1570 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1571 } else {
1572 LOG(FATAL) << "Unimplemented";
1573 }
1574}
1575
1576void ParallelMoveResolverARM::SpillScratch(int reg) {
1577 __ Push(static_cast<Register>(reg));
1578}
1579
1580void ParallelMoveResolverARM::RestoreScratch(int reg) {
1581 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001582}
1583
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001584} // namespace arm
1585} // namespace art