blob: a01e19d33f67147b5257f61f0d5a72afb906e9d3 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070019#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000021#include "mirror/array.h"
22#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070024#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010025#include "utils/assembler.h"
26#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010028#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000029
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031
32arm::ArmManagedRegister Location::AsArm() const {
33 return reg().AsArm();
34}
35
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace arm {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038static constexpr bool kExplicitStackOverflowCheck = false;
39
40static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
41static constexpr int kCurrentMethodStackOffset = 0;
42
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010043static Location ArmCoreLocation(Register reg) {
44 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
45}
46
47static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
48static constexpr size_t kRuntimeParameterCoreRegistersLength =
49 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010050static constexpr DRegister kRuntimeParameterFpuRegisters[] = { };
51static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010052
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053class InvokeRuntimeCallingConvention : public CallingConvention<Register, DRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010054 public:
55 InvokeRuntimeCallingConvention()
56 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010057 kRuntimeParameterCoreRegistersLength,
58 kRuntimeParameterFpuRegisters,
59 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010060
61 private:
62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63};
64
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
66
67class NullCheckSlowPathARM : public SlowPathCode {
68 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070
71 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
72 __ Bind(GetEntryLabel());
73 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
74 __ ldr(LR, Address(TR, offset));
75 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 }
78
79 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010080 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
82};
83
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010084class StackOverflowCheckSlowPathARM : public SlowPathCode {
85 public:
86 StackOverflowCheckSlowPathARM() {}
87
88 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
89 __ Bind(GetEntryLabel());
90 __ LoadFromOffset(kLoadWord, PC, TR,
91 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
92 }
93
94 private:
95 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
96};
97
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000098class SuspendCheckSlowPathARM : public SlowPathCode {
99 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100100 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
101 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000102
103 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
104 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100105 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000106 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
107 __ ldr(LR, Address(TR, offset));
108 __ blx(LR);
109 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100110 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100111 if (successor_ == nullptr) {
112 __ b(GetReturnLabel());
113 } else {
114 __ b(codegen->GetLabelOf(successor_));
115 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116 }
117
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100118 Label* GetReturnLabel() {
119 DCHECK(successor_ == nullptr);
120 return &return_label_;
121 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000122
123 private:
124 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100125 // If not null, the block to branch to after the suspend check.
126 HBasicBlock* const successor_;
127
128 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000129 Label return_label_;
130
131 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
132};
133
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100134class BoundsCheckSlowPathARM : public SlowPathCode {
135 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100136 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
137 Location index_location,
138 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100139 : instruction_(instruction),
140 index_location_(index_location),
141 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100142
143 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
144 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
145 __ Bind(GetEntryLabel());
146 InvokeRuntimeCallingConvention calling_convention;
147 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
148 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
149 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
150 __ ldr(LR, Address(TR, offset));
151 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100153 }
154
155 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100156 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100157 const Location index_location_;
158 const Location length_location_;
159
160 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
161};
162
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100163#undef __
164#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700165
166inline Condition ARMCondition(IfCondition cond) {
167 switch (cond) {
168 case kCondEQ: return EQ;
169 case kCondNE: return NE;
170 case kCondLT: return LT;
171 case kCondLE: return LE;
172 case kCondGT: return GT;
173 case kCondGE: return GE;
174 default:
175 LOG(FATAL) << "Unknown if condition";
176 }
177 return EQ; // Unreachable.
178}
179
180inline Condition ARMOppositeCondition(IfCondition cond) {
181 switch (cond) {
182 case kCondEQ: return NE;
183 case kCondNE: return EQ;
184 case kCondLT: return GE;
185 case kCondLE: return GT;
186 case kCondGT: return LE;
187 case kCondGE: return LT;
188 default:
189 LOG(FATAL) << "Unknown if condition";
190 }
191 return EQ; // Unreachable.
192}
193
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100194void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
195 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
196}
197
198void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
199 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
200}
201
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100202void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
203 __ str(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
204}
205
206void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
207 __ ldr(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
208}
209
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100210CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
211 : CodeGenerator(graph, kNumberOfRegIds),
212 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100213 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100214 move_resolver_(graph->GetArena(), this),
215 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100216
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100217size_t CodeGeneratorARM::FrameEntrySpillSize() const {
218 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
219}
220
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100221static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
222 return blocked_registers + kNumberOfAllocIds;
223}
224
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100225static bool* GetBlockedDRegisters(bool* blocked_registers) {
226 return blocked_registers + kNumberOfCoreRegisters + kNumberOfSRegisters;
227}
228
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100229ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
230 bool* blocked_registers) const {
231 switch (type) {
232 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100233 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
234 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100235 ArmManagedRegister pair =
236 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
237 blocked_registers[pair.AsRegisterPairLow()] = true;
238 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100239 // Block all other register pairs that share a register with `pair`.
240 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
241 ArmManagedRegister current =
242 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
243 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
244 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
245 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
246 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
247 blocked_register_pairs[i] = true;
248 }
249 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100250 return pair;
251 }
252
253 case Primitive::kPrimByte:
254 case Primitive::kPrimBoolean:
255 case Primitive::kPrimChar:
256 case Primitive::kPrimShort:
257 case Primitive::kPrimInt:
258 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100259 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
260 // Block all register pairs that contain `reg`.
261 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
262 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
263 ArmManagedRegister current =
264 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
265 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
266 blocked_register_pairs[i] = true;
267 }
268 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100269 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
270 }
271
272 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100273 case Primitive::kPrimDouble: {
274 int reg = AllocateFreeRegisterInternal(GetBlockedDRegisters(blocked_registers), kNumberOfDRegisters);
275 return ArmManagedRegister::FromDRegister(static_cast<DRegister>(reg));
276 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100277
278 case Primitive::kPrimVoid:
279 LOG(FATAL) << "Unreachable type " << type;
280 }
281
282 return ManagedRegister::NoRegister();
283}
284
285void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
286 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100287 bool* blocked_fpu_registers = GetBlockedDRegisters(blocked_registers);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100288
289 // Don't allocate the dalvik style register pair passing.
290 blocked_register_pairs[R1_R2] = true;
291
292 // Stack register, LR and PC are always reserved.
293 blocked_registers[SP] = true;
294 blocked_registers[LR] = true;
295 blocked_registers[PC] = true;
296
297 // Reserve R4 for suspend check.
298 blocked_registers[R4] = true;
299 blocked_register_pairs[R4_R5] = true;
300
301 // Reserve thread register.
302 blocked_registers[TR] = true;
303
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100304 // Reserve temp register.
305 blocked_registers[IP] = true;
306
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100307 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100308 // We always save and restore R6 and R7 to make sure we can use three
309 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100310 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100311 blocked_registers[R8] = true;
312 blocked_registers[R10] = true;
313 blocked_registers[R11] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100314
315 blocked_fpu_registers[D8] = true;
316 blocked_fpu_registers[D9] = true;
317 blocked_fpu_registers[D10] = true;
318 blocked_fpu_registers[D11] = true;
319 blocked_fpu_registers[D12] = true;
320 blocked_fpu_registers[D13] = true;
321 blocked_fpu_registers[D14] = true;
322 blocked_fpu_registers[D15] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100323}
324
325size_t CodeGeneratorARM::GetNumberOfRegisters() const {
326 return kNumberOfRegIds;
327}
328
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100329InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
330 : HGraphVisitor(graph),
331 assembler_(codegen->GetAssembler()),
332 codegen_(codegen) {}
333
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000334void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700335 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100336 if (!skip_overflow_check) {
337 if (kExplicitStackOverflowCheck) {
338 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
339 AddSlowPath(slow_path);
340
341 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
342 __ cmp(SP, ShifterOperand(IP));
343 __ b(slow_path->GetEntryLabel(), CC);
344 } else {
345 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
346 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100347 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100348 }
349 }
350
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100351 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
352 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000353
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100354 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100355 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000356 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000357}
358
359void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100360 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100361 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000362}
363
364void CodeGeneratorARM::Bind(Label* label) {
365 __ Bind(label);
366}
367
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100368Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
369 switch (load->GetType()) {
370 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100371 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100372 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
373 break;
374
375 case Primitive::kPrimInt:
376 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100377 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100378 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100379
380 case Primitive::kPrimBoolean:
381 case Primitive::kPrimByte:
382 case Primitive::kPrimChar:
383 case Primitive::kPrimShort:
384 case Primitive::kPrimVoid:
385 LOG(FATAL) << "Unexpected type " << load->GetType();
386 }
387
388 LOG(FATAL) << "Unreachable";
389 return Location();
390}
391
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100392Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
393 switch (type) {
394 case Primitive::kPrimBoolean:
395 case Primitive::kPrimByte:
396 case Primitive::kPrimChar:
397 case Primitive::kPrimShort:
398 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100399 case Primitive::kPrimFloat:
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100400 case Primitive::kPrimNot: {
401 uint32_t index = gp_index_++;
402 if (index < calling_convention.GetNumberOfRegisters()) {
403 return ArmCoreLocation(calling_convention.GetRegisterAt(index));
404 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100405 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100406 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100407 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100408
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100409 case Primitive::kPrimLong:
410 case Primitive::kPrimDouble: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100411 uint32_t index = gp_index_;
412 gp_index_ += 2;
413 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
414 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
415 calling_convention.GetRegisterPairAt(index)));
416 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
417 return Location::QuickParameter(index);
418 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100419 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100420 }
421 }
422
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100423 case Primitive::kPrimVoid:
424 LOG(FATAL) << "Unexpected parameter type " << type;
425 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100426 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100427 return Location();
428}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100429
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100430void CodeGeneratorARM::Move32(Location destination, Location source) {
431 if (source.Equals(destination)) {
432 return;
433 }
434 if (destination.IsRegister()) {
435 if (source.IsRegister()) {
436 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100437 } else if (source.IsFpuRegister()) {
438 __ vmovrs(destination.AsArm().AsCoreRegister(),
439 source.AsArm().AsOverlappingDRegisterLow());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100440 } else {
441 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
442 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100443 } else if (destination.IsFpuRegister()) {
444 if (source.IsRegister()) {
445 __ vmovsr(destination.AsArm().AsOverlappingDRegisterLow(),
446 source.AsArm().AsCoreRegister());
447 } else if (source.IsFpuRegister()) {
448 __ vmovs(destination.AsArm().AsOverlappingDRegisterLow(),
449 source.AsArm().AsOverlappingDRegisterLow());
450 } else {
451 __ vldrs(destination.AsArm().AsOverlappingDRegisterLow(),
452 Address(SP, source.GetStackIndex()));
453 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100454 } else {
455 DCHECK(destination.IsStackSlot());
456 if (source.IsRegister()) {
457 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100458 } else if (source.IsFpuRegister()) {
459 __ vstrs(source.AsArm().AsOverlappingDRegisterLow(),
460 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100461 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100462 DCHECK(source.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100463 __ ldr(IP, Address(SP, source.GetStackIndex()));
464 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100465 }
466 }
467}
468
469void CodeGeneratorARM::Move64(Location destination, Location source) {
470 if (source.Equals(destination)) {
471 return;
472 }
473 if (destination.IsRegister()) {
474 if (source.IsRegister()) {
475 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
476 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100477 } else if (source.IsFpuRegister()) {
478 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100479 } else if (source.IsQuickParameter()) {
480 uint32_t argument_index = source.GetQuickParameterIndex();
481 InvokeDexCallingConvention calling_convention;
482 __ Mov(destination.AsArm().AsRegisterPairLow(),
483 calling_convention.GetRegisterAt(argument_index));
484 __ ldr(destination.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100485 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100486 } else {
487 DCHECK(source.IsDoubleStackSlot());
488 if (destination.AsArm().AsRegisterPair() == R1_R2) {
489 __ ldr(R1, Address(SP, source.GetStackIndex()));
490 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
491 } else {
492 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
493 SP, source.GetStackIndex());
494 }
495 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100496 } else if (destination.IsFpuRegister()) {
497 if (source.IsDoubleStackSlot()) {
498 __ vldrd(destination.AsArm().AsDRegister(), Address(SP, source.GetStackIndex()));
499 } else {
500 LOG(FATAL) << "Unimplemented";
501 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100502 } else if (destination.IsQuickParameter()) {
503 InvokeDexCallingConvention calling_convention;
504 uint32_t argument_index = destination.GetQuickParameterIndex();
505 if (source.IsRegister()) {
506 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
507 __ str(source.AsArm().AsRegisterPairHigh(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100508 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100509 } else if (source.IsFpuRegister()) {
510 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100511 } else {
512 DCHECK(source.IsDoubleStackSlot());
513 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100514 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
515 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100516 }
517 } else {
518 DCHECK(destination.IsDoubleStackSlot());
519 if (source.IsRegister()) {
520 if (source.AsArm().AsRegisterPair() == R1_R2) {
521 __ str(R1, Address(SP, destination.GetStackIndex()));
522 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
523 } else {
524 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
525 SP, destination.GetStackIndex());
526 }
527 } else if (source.IsQuickParameter()) {
528 InvokeDexCallingConvention calling_convention;
529 uint32_t argument_index = source.GetQuickParameterIndex();
530 __ str(calling_convention.GetRegisterAt(argument_index),
531 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100532 __ ldr(R0,
533 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
534 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100535 } else if (source.IsFpuRegister()) {
536 __ vstrd(source.AsArm().AsDRegister(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100537 } else {
538 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100539 __ ldr(IP, Address(SP, source.GetStackIndex()));
540 __ str(IP, Address(SP, destination.GetStackIndex()));
541 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
542 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100543 }
544 }
545}
546
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100547void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100548 LocationSummary* locations = instruction->GetLocations();
549 if (locations != nullptr && locations->Out().Equals(location)) {
550 return;
551 }
552
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100553 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100554 int32_t value = instruction->AsIntConstant()->GetValue();
555 if (location.IsRegister()) {
556 __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
557 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100558 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100559 __ LoadImmediate(IP, value);
560 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100561 }
562 } else if (instruction->AsLongConstant() != nullptr) {
563 int64_t value = instruction->AsLongConstant()->GetValue();
564 if (location.IsRegister()) {
565 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
566 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
567 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100568 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100569 __ LoadImmediate(IP, Low32Bits(value));
570 __ str(IP, Address(SP, location.GetStackIndex()));
571 __ LoadImmediate(IP, High32Bits(value));
572 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100573 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100574 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100575 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
576 switch (instruction->GetType()) {
577 case Primitive::kPrimBoolean:
578 case Primitive::kPrimByte:
579 case Primitive::kPrimChar:
580 case Primitive::kPrimShort:
581 case Primitive::kPrimInt:
582 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100583 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100584 Move32(location, Location::StackSlot(stack_slot));
585 break;
586
587 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100589 Move64(location, Location::DoubleStackSlot(stack_slot));
590 break;
591
592 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100593 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100594 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000595 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100596 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100597 switch (instruction->GetType()) {
598 case Primitive::kPrimBoolean:
599 case Primitive::kPrimByte:
600 case Primitive::kPrimChar:
601 case Primitive::kPrimShort:
602 case Primitive::kPrimNot:
603 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100604 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100605 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100606 break;
607
608 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100609 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100610 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100611 break;
612
613 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100614 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100615 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000616 }
617}
618
619void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000620 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000621}
622
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000623void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000624 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100625 DCHECK(!successor->IsExitBlock());
626
627 HBasicBlock* block = got->GetBlock();
628 HInstruction* previous = got->GetPrevious();
629
630 HLoopInformation* info = block->GetLoopInformation();
631 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
632 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
633 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
634 return;
635 }
636
637 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
638 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
639 }
640 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000641 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000642 }
643}
644
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000645void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000646 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000647}
648
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000649void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000650 if (kIsDebugBuild) {
651 __ Comment("Unreachable");
652 __ bkpt(0);
653 }
654}
655
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000656void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100657 LocationSummary* locations =
658 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100659 HInstruction* cond = if_instr->InputAt(0);
660 DCHECK(cond->IsCondition());
661 HCondition* condition = cond->AsCondition();
662 if (condition->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100663 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100664 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000665}
666
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000667void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700668 HInstruction* cond = if_instr->InputAt(0);
669 DCHECK(cond->IsCondition());
670 HCondition* condition = cond->AsCondition();
671 if (condition->NeedsMaterialization()) {
672 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100673 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700674 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
675 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100676 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700677 } else {
678 // Condition has not been materialized, use its inputs as the comparison and its
679 // condition as the branch condition.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100680 LocationSummary* locations = condition->GetLocations();
681 if (locations->InAt(1).IsRegister()) {
682 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
683 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
684 } else {
685 DCHECK(locations->InAt(1).IsConstant());
686 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
687 ShifterOperand operand;
688 if (ShifterOperand::CanHoldArm(value, &operand)) {
689 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
690 } else {
691 Register temp = IP;
692 __ LoadImmediate(temp, value);
693 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
694 }
695 }
Dave Allison20dfc792014-06-16 20:44:29 -0700696 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
697 ARMCondition(condition->GetCondition()));
698 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100699
Dave Allison20dfc792014-06-16 20:44:29 -0700700 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
701 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000702 }
703}
704
Dave Allison20dfc792014-06-16 20:44:29 -0700705
706void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100707 LocationSummary* locations =
708 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100709 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
710 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100711 if (comp->NeedsMaterialization()) {
712 locations->SetOut(Location::RequiresRegister());
713 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000714}
715
Dave Allison20dfc792014-06-16 20:44:29 -0700716void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100717 if (!comp->NeedsMaterialization()) return;
718
719 LocationSummary* locations = comp->GetLocations();
720 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700721 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
722 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100723 } else {
724 DCHECK(locations->InAt(1).IsConstant());
725 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
726 ShifterOperand operand;
727 if (ShifterOperand::CanHoldArm(value, &operand)) {
728 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
729 } else {
730 Register temp = IP;
731 __ LoadImmediate(temp, value);
732 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
733 }
Dave Allison20dfc792014-06-16 20:44:29 -0700734 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100735 __ it(ARMCondition(comp->GetCondition()), kItElse);
736 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
737 ARMCondition(comp->GetCondition()));
738 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
739 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700740}
741
742void LocationsBuilderARM::VisitEqual(HEqual* comp) {
743 VisitCondition(comp);
744}
745
746void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
747 VisitCondition(comp);
748}
749
750void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
751 VisitCondition(comp);
752}
753
754void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
755 VisitCondition(comp);
756}
757
758void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
759 VisitCondition(comp);
760}
761
762void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
763 VisitCondition(comp);
764}
765
766void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
767 VisitCondition(comp);
768}
769
770void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
771 VisitCondition(comp);
772}
773
774void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
775 VisitCondition(comp);
776}
777
778void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
779 VisitCondition(comp);
780}
781
782void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
783 VisitCondition(comp);
784}
785
786void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
787 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000788}
789
790void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000791 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000792}
793
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000794void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
795 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000796}
797
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000798void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100799 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000800}
801
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000802void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100803 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000804}
805
806void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100807 LocationSummary* locations =
808 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 switch (store->InputAt(1)->GetType()) {
810 case Primitive::kPrimBoolean:
811 case Primitive::kPrimByte:
812 case Primitive::kPrimChar:
813 case Primitive::kPrimShort:
814 case Primitive::kPrimInt:
815 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100816 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100817 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
818 break;
819
820 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100821 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100822 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
823 break;
824
825 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100826 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100827 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000828}
829
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000830void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000831}
832
833void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100834 LocationSummary* locations =
835 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100836 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000837}
838
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000839void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000840}
841
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100842void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100843 LocationSummary* locations =
844 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100845 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100846}
847
848void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
849 // Will be generated at use site.
850}
851
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000852void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000853 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000854}
855
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000856void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
857 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000858}
859
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000860void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100861 LocationSummary* locations =
862 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863 switch (ret->InputAt(0)->GetType()) {
864 case Primitive::kPrimBoolean:
865 case Primitive::kPrimByte:
866 case Primitive::kPrimChar:
867 case Primitive::kPrimShort:
868 case Primitive::kPrimInt:
869 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100870 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100871 locations->SetInAt(0, ArmCoreLocation(R0));
872 break;
873
874 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100876 locations->SetInAt(
877 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100878 break;
879
880 default:
881 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
882 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000883}
884
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000885void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 if (kIsDebugBuild) {
887 switch (ret->InputAt(0)->GetType()) {
888 case Primitive::kPrimBoolean:
889 case Primitive::kPrimByte:
890 case Primitive::kPrimChar:
891 case Primitive::kPrimShort:
892 case Primitive::kPrimInt:
893 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100894 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100895 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
896 break;
897
898 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100899 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100900 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
901 break;
902
903 default:
904 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
905 }
906 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000907 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000908}
909
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000910void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100911 HandleInvoke(invoke);
912}
913
914void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
915 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
916}
917
918void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
919 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
920 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
921 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
922 invoke->GetIndexInDexCache() * kArmWordSize;
923
924 // TODO: Implement all kinds of calls:
925 // 1) boot -> boot
926 // 2) app -> boot
927 // 3) app -> app
928 //
929 // Currently we implement the app -> app logic, which looks up in the resolve cache.
930
931 // temp = method;
932 LoadCurrentMethod(temp);
933 // temp = temp->dex_cache_resolved_methods_;
934 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
935 // temp = temp[index_in_cache]
936 __ ldr(temp, Address(temp, index_in_cache));
937 // LR = temp[offset_of_quick_compiled_code]
938 __ ldr(LR, Address(temp,
939 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
940 // LR()
941 __ blx(LR);
942
943 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
944 DCHECK(!codegen_->IsLeafMethod());
945}
946
947void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
948 HandleInvoke(invoke);
949}
950
951void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100952 LocationSummary* locations =
953 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100954 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100955
956 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100957 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100958 HInstruction* input = invoke->InputAt(i);
959 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
960 }
961
962 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100963 case Primitive::kPrimBoolean:
964 case Primitive::kPrimByte:
965 case Primitive::kPrimChar:
966 case Primitive::kPrimShort:
967 case Primitive::kPrimInt:
968 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100969 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100970 locations->SetOut(ArmCoreLocation(R0));
971 break;
972
973 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100974 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100975 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
976 break;
977
978 case Primitive::kPrimVoid:
979 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100980 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000981}
982
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000983
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100984void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100985 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100986 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
987 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
988 LocationSummary* locations = invoke->GetLocations();
989 Location receiver = locations->InAt(0);
990 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
991 // temp = object->GetClass();
992 if (receiver.IsStackSlot()) {
993 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
994 __ ldr(temp, Address(temp, class_offset));
995 } else {
996 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
997 }
998 // temp = temp->GetMethodAt(method_offset);
999 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
1000 __ ldr(temp, Address(temp, method_offset));
1001 // LR = temp->GetEntryPoint();
1002 __ ldr(LR, Address(temp, entry_point));
1003 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001004 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001005 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001006 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001007}
1008
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001009void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001010 LocationSummary* locations =
1011 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001012 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001013 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001014 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001015 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
1016 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1017 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001018 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001019 break;
1020 }
1021
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001022 case Primitive::kPrimFloat:
1023 case Primitive::kPrimDouble: {
1024 locations->SetInAt(0, Location::RequiresFpuRegister());
1025 locations->SetInAt(1, Location::RequiresFpuRegister());
1026 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001027 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001028 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001029
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001030 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001031 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001032 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001033}
1034
1035void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1036 LocationSummary* locations = add->GetLocations();
1037 switch (add->GetResultType()) {
1038 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001039 if (locations->InAt(1).IsRegister()) {
1040 __ add(locations->Out().AsArm().AsCoreRegister(),
1041 locations->InAt(0).AsArm().AsCoreRegister(),
1042 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1043 } else {
1044 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1045 locations->InAt(0).AsArm().AsCoreRegister(),
1046 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1047 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001048 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001049
1050 case Primitive::kPrimLong:
1051 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
1052 locations->InAt(0).AsArm().AsRegisterPairLow(),
1053 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1054 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
1055 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1056 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1057 break;
1058
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001059 case Primitive::kPrimFloat:
1060 __ vadds(locations->Out().AsArm().AsOverlappingDRegisterLow(),
1061 locations->InAt(0).AsArm().AsOverlappingDRegisterLow(),
1062 locations->InAt(1).AsArm().AsOverlappingDRegisterLow());
1063 break;
1064
1065 case Primitive::kPrimDouble:
1066 __ vaddd(locations->Out().AsArm().AsDRegister(),
1067 locations->InAt(0).AsArm().AsDRegister(),
1068 locations->InAt(1).AsArm().AsDRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001069 break;
1070
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001071 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001072 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001073 }
1074}
1075
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001076void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001077 LocationSummary* locations =
1078 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001079 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001080 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001081 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001082 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1083 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1084 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001085 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001086 break;
1087 }
1088
1089 case Primitive::kPrimBoolean:
1090 case Primitive::kPrimByte:
1091 case Primitive::kPrimChar:
1092 case Primitive::kPrimShort:
1093 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1094 break;
1095
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001096 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001098 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001099}
1100
1101void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1102 LocationSummary* locations = sub->GetLocations();
1103 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001104 case Primitive::kPrimInt: {
1105 if (locations->InAt(1).IsRegister()) {
1106 __ sub(locations->Out().AsArm().AsCoreRegister(),
1107 locations->InAt(0).AsArm().AsCoreRegister(),
1108 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1109 } else {
1110 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1111 locations->InAt(0).AsArm().AsCoreRegister(),
1112 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1113 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001114 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001115 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001116
1117 case Primitive::kPrimLong:
1118 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1119 locations->InAt(0).AsArm().AsRegisterPairLow(),
1120 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1121 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1122 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1123 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1124 break;
1125
1126 case Primitive::kPrimBoolean:
1127 case Primitive::kPrimByte:
1128 case Primitive::kPrimChar:
1129 case Primitive::kPrimShort:
1130 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1131 break;
1132
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001133 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001134 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001135 }
1136}
1137
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001138void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001139 LocationSummary* locations =
1140 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001141 InvokeRuntimeCallingConvention calling_convention;
1142 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1143 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001144 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001145}
1146
1147void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1148 InvokeRuntimeCallingConvention calling_convention;
1149 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1150 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1151
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001152 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001153 __ ldr(LR, Address(TR, offset));
1154 __ blx(LR);
1155
Nicolas Geoffray39468442014-09-02 15:17:15 +01001156 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001157 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001158}
1159
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001160void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001161 LocationSummary* locations =
1162 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001163 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1164 if (location.IsStackSlot()) {
1165 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1166 } else if (location.IsDoubleStackSlot()) {
1167 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001168 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001169 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001170}
1171
1172void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001173 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001174}
1175
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001176void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001177 LocationSummary* locations =
1178 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001179 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001180 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001181}
1182
1183void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1184 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001185 __ eor(locations->Out().AsArm().AsCoreRegister(),
1186 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001187}
1188
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001189void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001190 LocationSummary* locations =
1191 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001192 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1193 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001194 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001195}
1196
1197void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1198 Label greater, done;
1199 LocationSummary* locations = compare->GetLocations();
1200 switch (compare->InputAt(0)->GetType()) {
1201 case Primitive::kPrimLong: {
1202 Register output = locations->Out().AsArm().AsCoreRegister();
1203 ArmManagedRegister left = locations->InAt(0).AsArm();
1204 ArmManagedRegister right = locations->InAt(1).AsArm();
1205 Label less, greater, done;
1206 __ cmp(left.AsRegisterPairHigh(),
1207 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1208 __ b(&less, LT);
1209 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001210 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1211 // the status flags.
1212 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001213 __ cmp(left.AsRegisterPairLow(),
1214 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001215 __ b(&done, EQ);
1216 __ b(&less, CC);
1217
1218 __ Bind(&greater);
1219 __ LoadImmediate(output, 1);
1220 __ b(&done);
1221
1222 __ Bind(&less);
1223 __ LoadImmediate(output, -1);
1224
1225 __ Bind(&done);
1226 break;
1227 }
1228 default:
1229 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1230 }
1231}
1232
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001233void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001234 LocationSummary* locations =
1235 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001236 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1237 locations->SetInAt(i, Location::Any());
1238 }
1239 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001240}
1241
1242void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001243 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001244}
1245
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001246void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001247 LocationSummary* locations =
1248 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001249 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1250 bool dies_at_entry = !is_object_type;
1251 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1252 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001253 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001254 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001255 locations->AddTemp(Location::RequiresRegister());
1256 locations->AddTemp(Location::RequiresRegister());
1257 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001258}
1259
1260void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1261 LocationSummary* locations = instruction->GetLocations();
1262 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1263 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001264 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001265
1266 switch (field_type) {
1267 case Primitive::kPrimBoolean:
1268 case Primitive::kPrimByte: {
1269 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1270 __ StoreToOffset(kStoreByte, value, obj, offset);
1271 break;
1272 }
1273
1274 case Primitive::kPrimShort:
1275 case Primitive::kPrimChar: {
1276 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1277 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1278 break;
1279 }
1280
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001281 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001282 case Primitive::kPrimNot: {
1283 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1284 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001285 if (field_type == Primitive::kPrimNot) {
1286 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1287 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1288 codegen_->MarkGCCard(temp, card, obj, value);
1289 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001290 break;
1291 }
1292
1293 case Primitive::kPrimLong: {
1294 ArmManagedRegister value = locations->InAt(1).AsArm();
1295 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1296 break;
1297 }
1298
1299 case Primitive::kPrimFloat:
1300 case Primitive::kPrimDouble:
1301 LOG(FATAL) << "Unimplemented register type " << field_type;
1302
1303 case Primitive::kPrimVoid:
1304 LOG(FATAL) << "Unreachable type " << field_type;
1305 }
1306}
1307
1308void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001309 LocationSummary* locations =
1310 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001311 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001312 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001313}
1314
1315void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1316 LocationSummary* locations = instruction->GetLocations();
1317 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1318 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1319
1320 switch (instruction->GetType()) {
1321 case Primitive::kPrimBoolean: {
1322 Register out = locations->Out().AsArm().AsCoreRegister();
1323 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1324 break;
1325 }
1326
1327 case Primitive::kPrimByte: {
1328 Register out = locations->Out().AsArm().AsCoreRegister();
1329 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1330 break;
1331 }
1332
1333 case Primitive::kPrimShort: {
1334 Register out = locations->Out().AsArm().AsCoreRegister();
1335 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1336 break;
1337 }
1338
1339 case Primitive::kPrimChar: {
1340 Register out = locations->Out().AsArm().AsCoreRegister();
1341 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1342 break;
1343 }
1344
1345 case Primitive::kPrimInt:
1346 case Primitive::kPrimNot: {
1347 Register out = locations->Out().AsArm().AsCoreRegister();
1348 __ LoadFromOffset(kLoadWord, out, obj, offset);
1349 break;
1350 }
1351
1352 case Primitive::kPrimLong: {
1353 // TODO: support volatile.
1354 ArmManagedRegister out = locations->Out().AsArm();
1355 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1356 break;
1357 }
1358
1359 case Primitive::kPrimFloat:
1360 case Primitive::kPrimDouble:
1361 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1362
1363 case Primitive::kPrimVoid:
1364 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1365 }
1366}
1367
1368void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001369 LocationSummary* locations =
1370 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001371 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001372 if (instruction->HasUses()) {
1373 locations->SetOut(Location::SameAsFirstInput());
1374 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001375}
1376
1377void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001378 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001379 codegen_->AddSlowPath(slow_path);
1380
1381 LocationSummary* locations = instruction->GetLocations();
1382 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001383
1384 if (obj.IsRegister()) {
1385 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001386 __ b(slow_path->GetEntryLabel(), EQ);
1387 } else {
1388 DCHECK(obj.IsConstant()) << obj;
1389 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1390 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001391 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001392}
1393
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001394void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001395 LocationSummary* locations =
1396 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001397 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1398 locations->SetInAt(
1399 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001400 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001401}
1402
1403void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1404 LocationSummary* locations = instruction->GetLocations();
1405 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1406 Location index = locations->InAt(1);
1407
1408 switch (instruction->GetType()) {
1409 case Primitive::kPrimBoolean: {
1410 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1411 Register out = locations->Out().AsArm().AsCoreRegister();
1412 if (index.IsConstant()) {
1413 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1414 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1415 } else {
1416 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1417 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1418 }
1419 break;
1420 }
1421
1422 case Primitive::kPrimByte: {
1423 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1424 Register out = locations->Out().AsArm().AsCoreRegister();
1425 if (index.IsConstant()) {
1426 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1427 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1428 } else {
1429 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1430 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1431 }
1432 break;
1433 }
1434
1435 case Primitive::kPrimShort: {
1436 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1437 Register out = locations->Out().AsArm().AsCoreRegister();
1438 if (index.IsConstant()) {
1439 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1440 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1441 } else {
1442 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1443 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1444 }
1445 break;
1446 }
1447
1448 case Primitive::kPrimChar: {
1449 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1450 Register out = locations->Out().AsArm().AsCoreRegister();
1451 if (index.IsConstant()) {
1452 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1453 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1454 } else {
1455 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1456 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1457 }
1458 break;
1459 }
1460
1461 case Primitive::kPrimInt:
1462 case Primitive::kPrimNot: {
1463 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1464 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1465 Register out = locations->Out().AsArm().AsCoreRegister();
1466 if (index.IsConstant()) {
1467 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1468 __ LoadFromOffset(kLoadWord, out, obj, offset);
1469 } else {
1470 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1471 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1472 }
1473 break;
1474 }
1475
1476 case Primitive::kPrimLong: {
1477 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1478 ArmManagedRegister out = locations->Out().AsArm();
1479 if (index.IsConstant()) {
1480 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1481 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1482 } else {
1483 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1484 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1485 }
1486 break;
1487 }
1488
1489 case Primitive::kPrimFloat:
1490 case Primitive::kPrimDouble:
1491 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1492
1493 case Primitive::kPrimVoid:
1494 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1495 }
1496}
1497
1498void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001499 Primitive::Type value_type = instruction->GetComponentType();
1500 bool is_object = value_type == Primitive::kPrimNot;
1501 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1502 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1503 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001504 InvokeRuntimeCallingConvention calling_convention;
1505 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1506 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1507 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001508 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001509 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1510 locations->SetInAt(
1511 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1512 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001513 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001514}
1515
1516void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1517 LocationSummary* locations = instruction->GetLocations();
1518 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1519 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001520 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001521
1522 switch (value_type) {
1523 case Primitive::kPrimBoolean:
1524 case Primitive::kPrimByte: {
1525 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1526 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1527 if (index.IsConstant()) {
1528 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1529 __ StoreToOffset(kStoreByte, value, obj, offset);
1530 } else {
1531 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1532 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1533 }
1534 break;
1535 }
1536
1537 case Primitive::kPrimShort:
1538 case Primitive::kPrimChar: {
1539 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1540 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1541 if (index.IsConstant()) {
1542 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1543 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1544 } else {
1545 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1546 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1547 }
1548 break;
1549 }
1550
1551 case Primitive::kPrimInt: {
1552 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1553 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1554 if (index.IsConstant()) {
1555 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1556 __ StoreToOffset(kStoreWord, value, obj, offset);
1557 } else {
1558 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1559 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1560 }
1561 break;
1562 }
1563
1564 case Primitive::kPrimNot: {
1565 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1566 __ ldr(LR, Address(TR, offset));
1567 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001568 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001569 DCHECK(!codegen_->IsLeafMethod());
1570 break;
1571 }
1572
1573 case Primitive::kPrimLong: {
1574 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1575 ArmManagedRegister value = locations->InAt(2).AsArm();
1576 if (index.IsConstant()) {
1577 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1578 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1579 } else {
1580 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1581 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1582 }
1583 break;
1584 }
1585
1586 case Primitive::kPrimFloat:
1587 case Primitive::kPrimDouble:
1588 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1589
1590 case Primitive::kPrimVoid:
1591 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1592 }
1593}
1594
1595void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001596 LocationSummary* locations =
1597 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001598 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001599 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001600}
1601
1602void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1603 LocationSummary* locations = instruction->GetLocations();
1604 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1605 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1606 Register out = locations->Out().AsArm().AsCoreRegister();
1607 __ LoadFromOffset(kLoadWord, out, obj, offset);
1608}
1609
1610void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001611 LocationSummary* locations =
1612 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001613 locations->SetInAt(0, Location::RequiresRegister());
1614 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001615 if (instruction->HasUses()) {
1616 locations->SetOut(Location::SameAsFirstInput());
1617 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001618}
1619
1620void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1621 LocationSummary* locations = instruction->GetLocations();
1622 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001623 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001624 codegen_->AddSlowPath(slow_path);
1625
1626 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1627 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1628
1629 __ cmp(index, ShifterOperand(length));
1630 __ b(slow_path->GetEntryLabel(), CS);
1631}
1632
1633void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1634 Label is_null;
1635 __ CompareAndBranchIfZero(value, &is_null);
1636 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1637 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1638 __ strb(card, Address(card, temp));
1639 __ Bind(&is_null);
1640}
1641
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001642void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1643 temp->SetLocations(nullptr);
1644}
1645
1646void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1647 // Nothing to do, this is driven by the code generator.
1648}
1649
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001650void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001651 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001652}
1653
1654void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001655 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1656}
1657
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001658void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1659 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1660}
1661
1662void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001663 HBasicBlock* block = instruction->GetBlock();
1664 if (block->GetLoopInformation() != nullptr) {
1665 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1666 // The back edge will generate the suspend check.
1667 return;
1668 }
1669 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1670 // The goto will generate the suspend check.
1671 return;
1672 }
1673 GenerateSuspendCheck(instruction, nullptr);
1674}
1675
1676void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1677 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001678 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001679 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001680 codegen_->AddSlowPath(slow_path);
1681
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001682 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001683 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001684 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001685 __ Bind(slow_path->GetReturnLabel());
1686 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001687 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001688 __ b(slow_path->GetEntryLabel());
1689 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001690}
1691
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001692ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1693 return codegen_->GetAssembler();
1694}
1695
1696void ParallelMoveResolverARM::EmitMove(size_t index) {
1697 MoveOperands* move = moves_.Get(index);
1698 Location source = move->GetSource();
1699 Location destination = move->GetDestination();
1700
1701 if (source.IsRegister()) {
1702 if (destination.IsRegister()) {
1703 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1704 } else {
1705 DCHECK(destination.IsStackSlot());
1706 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1707 SP, destination.GetStackIndex());
1708 }
1709 } else if (source.IsStackSlot()) {
1710 if (destination.IsRegister()) {
1711 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1712 SP, source.GetStackIndex());
1713 } else {
1714 DCHECK(destination.IsStackSlot());
1715 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1716 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1717 }
1718 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001719 DCHECK(source.IsConstant());
1720 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1721 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1722 if (destination.IsRegister()) {
1723 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1724 } else {
1725 DCHECK(destination.IsStackSlot());
1726 __ LoadImmediate(IP, value);
1727 __ str(IP, Address(SP, destination.GetStackIndex()));
1728 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001729 }
1730}
1731
1732void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1733 __ Mov(IP, reg);
1734 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1735 __ StoreToOffset(kStoreWord, IP, SP, mem);
1736}
1737
1738void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1739 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1740 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1741 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1742 SP, mem1 + stack_offset);
1743 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1744 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1745 SP, mem2 + stack_offset);
1746 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1747}
1748
1749void ParallelMoveResolverARM::EmitSwap(size_t index) {
1750 MoveOperands* move = moves_.Get(index);
1751 Location source = move->GetSource();
1752 Location destination = move->GetDestination();
1753
1754 if (source.IsRegister() && destination.IsRegister()) {
1755 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1756 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1757 __ Mov(IP, source.AsArm().AsCoreRegister());
1758 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1759 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1760 } else if (source.IsRegister() && destination.IsStackSlot()) {
1761 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1762 } else if (source.IsStackSlot() && destination.IsRegister()) {
1763 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1764 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1765 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1766 } else {
1767 LOG(FATAL) << "Unimplemented";
1768 }
1769}
1770
1771void ParallelMoveResolverARM::SpillScratch(int reg) {
1772 __ Push(static_cast<Register>(reg));
1773}
1774
1775void ParallelMoveResolverARM::RestoreScratch(int reg) {
1776 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001777}
1778
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001779} // namespace arm
1780} // namespace art