blob: d11690590308959c474d911ef5de43327fcbbc49 [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);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100660 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100661 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100662 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000663}
664
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000665void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700666 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100667 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700668 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100669 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Dave Allison20dfc792014-06-16 20:44:29 -0700670 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
671 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100672 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700673 } else {
674 // Condition has not been materialized, use its inputs as the comparison and its
675 // condition as the branch condition.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100676 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100677 if (locations->InAt(1).IsRegister()) {
678 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
679 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
680 } else {
681 DCHECK(locations->InAt(1).IsConstant());
682 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
683 ShifterOperand operand;
684 if (ShifterOperand::CanHoldArm(value, &operand)) {
685 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
686 } else {
687 Register temp = IP;
688 __ LoadImmediate(temp, value);
689 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
690 }
691 }
Dave Allison20dfc792014-06-16 20:44:29 -0700692 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100693 ARMCondition(cond->AsCondition()->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700694 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100695
Dave Allison20dfc792014-06-16 20:44:29 -0700696 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
697 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000698 }
699}
700
Dave Allison20dfc792014-06-16 20:44:29 -0700701
702void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100703 LocationSummary* locations =
704 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100705 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
706 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100707 if (comp->NeedsMaterialization()) {
708 locations->SetOut(Location::RequiresRegister());
709 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000710}
711
Dave Allison20dfc792014-06-16 20:44:29 -0700712void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100713 if (!comp->NeedsMaterialization()) return;
714
715 LocationSummary* locations = comp->GetLocations();
716 if (locations->InAt(1).IsRegister()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700717 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
718 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100719 } else {
720 DCHECK(locations->InAt(1).IsConstant());
721 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
722 ShifterOperand operand;
723 if (ShifterOperand::CanHoldArm(value, &operand)) {
724 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value));
725 } else {
726 Register temp = IP;
727 __ LoadImmediate(temp, value);
728 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
729 }
Dave Allison20dfc792014-06-16 20:44:29 -0700730 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100731 __ it(ARMCondition(comp->GetCondition()), kItElse);
732 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
733 ARMCondition(comp->GetCondition()));
734 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
735 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700736}
737
738void LocationsBuilderARM::VisitEqual(HEqual* comp) {
739 VisitCondition(comp);
740}
741
742void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
743 VisitCondition(comp);
744}
745
746void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
747 VisitCondition(comp);
748}
749
750void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
751 VisitCondition(comp);
752}
753
754void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
755 VisitCondition(comp);
756}
757
758void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
759 VisitCondition(comp);
760}
761
762void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
763 VisitCondition(comp);
764}
765
766void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
767 VisitCondition(comp);
768}
769
770void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
771 VisitCondition(comp);
772}
773
774void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
775 VisitCondition(comp);
776}
777
778void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
779 VisitCondition(comp);
780}
781
782void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
783 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000784}
785
786void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000787 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000788}
789
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000790void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
791 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000792}
793
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000794void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100795 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000796}
797
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000798void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100799 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000800}
801
802void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100803 LocationSummary* locations =
804 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100805 switch (store->InputAt(1)->GetType()) {
806 case Primitive::kPrimBoolean:
807 case Primitive::kPrimByte:
808 case Primitive::kPrimChar:
809 case Primitive::kPrimShort:
810 case Primitive::kPrimInt:
811 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100812 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
814 break;
815
816 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100817 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100818 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
819 break;
820
821 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100822 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100823 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000824}
825
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000826void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000827}
828
829void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100830 LocationSummary* locations =
831 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100832 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000833}
834
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000835void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000836}
837
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100838void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100839 LocationSummary* locations =
840 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100841 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100842}
843
844void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
845 // Will be generated at use site.
846}
847
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000848void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000849 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000850}
851
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000852void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
853 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000854}
855
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000856void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100857 LocationSummary* locations =
858 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100859 switch (ret->InputAt(0)->GetType()) {
860 case Primitive::kPrimBoolean:
861 case Primitive::kPrimByte:
862 case Primitive::kPrimChar:
863 case Primitive::kPrimShort:
864 case Primitive::kPrimInt:
865 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100867 locations->SetInAt(0, ArmCoreLocation(R0));
868 break;
869
870 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100871 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100872 locations->SetInAt(
873 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 break;
875
876 default:
877 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
878 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000879}
880
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000881void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 if (kIsDebugBuild) {
883 switch (ret->InputAt(0)->GetType()) {
884 case Primitive::kPrimBoolean:
885 case Primitive::kPrimByte:
886 case Primitive::kPrimChar:
887 case Primitive::kPrimShort:
888 case Primitive::kPrimInt:
889 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100890 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100891 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
892 break;
893
894 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100895 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100896 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
897 break;
898
899 default:
900 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
901 }
902 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000903 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000904}
905
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000906void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100907 HandleInvoke(invoke);
908}
909
910void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
911 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
912}
913
914void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
915 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
916 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
917 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
918 invoke->GetIndexInDexCache() * kArmWordSize;
919
920 // TODO: Implement all kinds of calls:
921 // 1) boot -> boot
922 // 2) app -> boot
923 // 3) app -> app
924 //
925 // Currently we implement the app -> app logic, which looks up in the resolve cache.
926
927 // temp = method;
928 LoadCurrentMethod(temp);
929 // temp = temp->dex_cache_resolved_methods_;
930 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
931 // temp = temp[index_in_cache]
932 __ ldr(temp, Address(temp, index_in_cache));
933 // LR = temp[offset_of_quick_compiled_code]
934 __ ldr(LR, Address(temp,
935 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
936 // LR()
937 __ blx(LR);
938
939 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
940 DCHECK(!codegen_->IsLeafMethod());
941}
942
943void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
944 HandleInvoke(invoke);
945}
946
947void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100948 LocationSummary* locations =
949 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100950 locations->AddTemp(ArmCoreLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100951
952 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100953 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100954 HInstruction* input = invoke->InputAt(i);
955 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
956 }
957
958 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100959 case Primitive::kPrimBoolean:
960 case Primitive::kPrimByte:
961 case Primitive::kPrimChar:
962 case Primitive::kPrimShort:
963 case Primitive::kPrimInt:
964 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100965 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100966 locations->SetOut(ArmCoreLocation(R0));
967 break;
968
969 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100970 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100971 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
972 break;
973
974 case Primitive::kPrimVoid:
975 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100976 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000977}
978
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000979
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100980void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100981 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100982 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
983 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
984 LocationSummary* locations = invoke->GetLocations();
985 Location receiver = locations->InAt(0);
986 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
987 // temp = object->GetClass();
988 if (receiver.IsStackSlot()) {
989 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
990 __ ldr(temp, Address(temp, class_offset));
991 } else {
992 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
993 }
994 // temp = temp->GetMethodAt(method_offset);
995 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
996 __ ldr(temp, Address(temp, method_offset));
997 // LR = temp->GetEntryPoint();
998 __ ldr(LR, Address(temp, entry_point));
999 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001000 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001001 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001002 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001003}
1004
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001005void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001006 LocationSummary* locations =
1007 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001008 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001009 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001010 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001011 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
1012 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1013 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001014 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001015 break;
1016 }
1017
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001018 case Primitive::kPrimFloat:
1019 case Primitive::kPrimDouble: {
1020 locations->SetInAt(0, Location::RequiresFpuRegister());
1021 locations->SetInAt(1, Location::RequiresFpuRegister());
1022 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001023 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001024 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001025
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001026 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001027 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001028 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001029}
1030
1031void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1032 LocationSummary* locations = add->GetLocations();
1033 switch (add->GetResultType()) {
1034 case Primitive::kPrimInt:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001035 if (locations->InAt(1).IsRegister()) {
1036 __ add(locations->Out().AsArm().AsCoreRegister(),
1037 locations->InAt(0).AsArm().AsCoreRegister(),
1038 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1039 } else {
1040 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1041 locations->InAt(0).AsArm().AsCoreRegister(),
1042 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1043 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001044 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001045
1046 case Primitive::kPrimLong:
1047 __ adds(locations->Out().AsArm().AsRegisterPairLow(),
1048 locations->InAt(0).AsArm().AsRegisterPairLow(),
1049 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1050 __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
1051 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1052 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1053 break;
1054
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001055 case Primitive::kPrimFloat:
1056 __ vadds(locations->Out().AsArm().AsOverlappingDRegisterLow(),
1057 locations->InAt(0).AsArm().AsOverlappingDRegisterLow(),
1058 locations->InAt(1).AsArm().AsOverlappingDRegisterLow());
1059 break;
1060
1061 case Primitive::kPrimDouble:
1062 __ vaddd(locations->Out().AsArm().AsDRegister(),
1063 locations->InAt(0).AsArm().AsDRegister(),
1064 locations->InAt(1).AsArm().AsDRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001065 break;
1066
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001067 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001068 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001069 }
1070}
1071
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001072void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001073 LocationSummary* locations =
1074 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001075 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001076 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001077 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001078 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1079 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1080 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001081 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001082 break;
1083 }
1084
1085 case Primitive::kPrimBoolean:
1086 case Primitive::kPrimByte:
1087 case Primitive::kPrimChar:
1088 case Primitive::kPrimShort:
1089 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1090 break;
1091
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001092 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001093 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001094 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001095}
1096
1097void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1098 LocationSummary* locations = sub->GetLocations();
1099 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001100 case Primitive::kPrimInt: {
1101 if (locations->InAt(1).IsRegister()) {
1102 __ sub(locations->Out().AsArm().AsCoreRegister(),
1103 locations->InAt(0).AsArm().AsCoreRegister(),
1104 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
1105 } else {
1106 __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
1107 locations->InAt(0).AsArm().AsCoreRegister(),
1108 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1109 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001110 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001111 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001112
1113 case Primitive::kPrimLong:
1114 __ subs(locations->Out().AsArm().AsRegisterPairLow(),
1115 locations->InAt(0).AsArm().AsRegisterPairLow(),
1116 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
1117 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
1118 locations->InAt(0).AsArm().AsRegisterPairHigh(),
1119 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
1120 break;
1121
1122 case Primitive::kPrimBoolean:
1123 case Primitive::kPrimByte:
1124 case Primitive::kPrimChar:
1125 case Primitive::kPrimShort:
1126 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1127 break;
1128
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001129 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001130 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001131 }
1132}
1133
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001134void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001135 LocationSummary* locations =
1136 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001137 InvokeRuntimeCallingConvention calling_convention;
1138 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1139 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001140 locations->SetOut(ArmCoreLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001141}
1142
1143void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1144 InvokeRuntimeCallingConvention calling_convention;
1145 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1146 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1147
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001148 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001149 __ ldr(LR, Address(TR, offset));
1150 __ blx(LR);
1151
Nicolas Geoffray39468442014-09-02 15:17:15 +01001152 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001153 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001154}
1155
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001156void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001157 LocationSummary* locations =
1158 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001159 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1160 if (location.IsStackSlot()) {
1161 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1162 } else if (location.IsDoubleStackSlot()) {
1163 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001164 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001165 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001166}
1167
1168void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001169 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001170}
1171
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001172void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001173 LocationSummary* locations =
1174 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001175 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001176 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001177}
1178
1179void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1180 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001181 __ eor(locations->Out().AsArm().AsCoreRegister(),
1182 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001183}
1184
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001185void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001186 LocationSummary* locations =
1187 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001188 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1189 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001190 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001191}
1192
1193void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1194 Label greater, done;
1195 LocationSummary* locations = compare->GetLocations();
1196 switch (compare->InputAt(0)->GetType()) {
1197 case Primitive::kPrimLong: {
1198 Register output = locations->Out().AsArm().AsCoreRegister();
1199 ArmManagedRegister left = locations->InAt(0).AsArm();
1200 ArmManagedRegister right = locations->InAt(1).AsArm();
1201 Label less, greater, done;
1202 __ cmp(left.AsRegisterPairHigh(),
1203 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare.
1204 __ b(&less, LT);
1205 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001206 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1207 // the status flags.
1208 __ LoadImmediate(output, 0);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001209 __ cmp(left.AsRegisterPairLow(),
1210 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001211 __ b(&done, EQ);
1212 __ b(&less, CC);
1213
1214 __ Bind(&greater);
1215 __ LoadImmediate(output, 1);
1216 __ b(&done);
1217
1218 __ Bind(&less);
1219 __ LoadImmediate(output, -1);
1220
1221 __ Bind(&done);
1222 break;
1223 }
1224 default:
1225 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1226 }
1227}
1228
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001229void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001230 LocationSummary* locations =
1231 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001232 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1233 locations->SetInAt(i, Location::Any());
1234 }
1235 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001236}
1237
1238void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001239 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001240}
1241
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001242void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001243 LocationSummary* locations =
1244 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001245 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1246 bool dies_at_entry = !is_object_type;
1247 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1248 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001249 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001250 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001251 locations->AddTemp(Location::RequiresRegister());
1252 locations->AddTemp(Location::RequiresRegister());
1253 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001254}
1255
1256void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1257 LocationSummary* locations = instruction->GetLocations();
1258 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1259 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001260 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001261
1262 switch (field_type) {
1263 case Primitive::kPrimBoolean:
1264 case Primitive::kPrimByte: {
1265 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1266 __ StoreToOffset(kStoreByte, value, obj, offset);
1267 break;
1268 }
1269
1270 case Primitive::kPrimShort:
1271 case Primitive::kPrimChar: {
1272 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1273 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1274 break;
1275 }
1276
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001277 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001278 case Primitive::kPrimNot: {
1279 Register value = locations->InAt(1).AsArm().AsCoreRegister();
1280 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001281 if (field_type == Primitive::kPrimNot) {
1282 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
1283 Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
1284 codegen_->MarkGCCard(temp, card, obj, value);
1285 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001286 break;
1287 }
1288
1289 case Primitive::kPrimLong: {
1290 ArmManagedRegister value = locations->InAt(1).AsArm();
1291 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1292 break;
1293 }
1294
1295 case Primitive::kPrimFloat:
1296 case Primitive::kPrimDouble:
1297 LOG(FATAL) << "Unimplemented register type " << field_type;
1298
1299 case Primitive::kPrimVoid:
1300 LOG(FATAL) << "Unreachable type " << field_type;
1301 }
1302}
1303
1304void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001305 LocationSummary* locations =
1306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001307 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001308 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001309}
1310
1311void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1312 LocationSummary* locations = instruction->GetLocations();
1313 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1314 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1315
1316 switch (instruction->GetType()) {
1317 case Primitive::kPrimBoolean: {
1318 Register out = locations->Out().AsArm().AsCoreRegister();
1319 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1320 break;
1321 }
1322
1323 case Primitive::kPrimByte: {
1324 Register out = locations->Out().AsArm().AsCoreRegister();
1325 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1326 break;
1327 }
1328
1329 case Primitive::kPrimShort: {
1330 Register out = locations->Out().AsArm().AsCoreRegister();
1331 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1332 break;
1333 }
1334
1335 case Primitive::kPrimChar: {
1336 Register out = locations->Out().AsArm().AsCoreRegister();
1337 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1338 break;
1339 }
1340
1341 case Primitive::kPrimInt:
1342 case Primitive::kPrimNot: {
1343 Register out = locations->Out().AsArm().AsCoreRegister();
1344 __ LoadFromOffset(kLoadWord, out, obj, offset);
1345 break;
1346 }
1347
1348 case Primitive::kPrimLong: {
1349 // TODO: support volatile.
1350 ArmManagedRegister out = locations->Out().AsArm();
1351 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1352 break;
1353 }
1354
1355 case Primitive::kPrimFloat:
1356 case Primitive::kPrimDouble:
1357 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1358
1359 case Primitive::kPrimVoid:
1360 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1361 }
1362}
1363
1364void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001365 LocationSummary* locations =
1366 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001367 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001368 if (instruction->HasUses()) {
1369 locations->SetOut(Location::SameAsFirstInput());
1370 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001371}
1372
1373void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001374 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001375 codegen_->AddSlowPath(slow_path);
1376
1377 LocationSummary* locations = instruction->GetLocations();
1378 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001379
1380 if (obj.IsRegister()) {
1381 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001382 __ b(slow_path->GetEntryLabel(), EQ);
1383 } else {
1384 DCHECK(obj.IsConstant()) << obj;
1385 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1386 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001387 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001388}
1389
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001390void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001391 LocationSummary* locations =
1392 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001393 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1394 locations->SetInAt(
1395 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001396 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001397}
1398
1399void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1400 LocationSummary* locations = instruction->GetLocations();
1401 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1402 Location index = locations->InAt(1);
1403
1404 switch (instruction->GetType()) {
1405 case Primitive::kPrimBoolean: {
1406 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1407 Register out = locations->Out().AsArm().AsCoreRegister();
1408 if (index.IsConstant()) {
1409 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1410 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1411 } else {
1412 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1413 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1414 }
1415 break;
1416 }
1417
1418 case Primitive::kPrimByte: {
1419 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1420 Register out = locations->Out().AsArm().AsCoreRegister();
1421 if (index.IsConstant()) {
1422 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1423 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1424 } else {
1425 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1426 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1427 }
1428 break;
1429 }
1430
1431 case Primitive::kPrimShort: {
1432 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1433 Register out = locations->Out().AsArm().AsCoreRegister();
1434 if (index.IsConstant()) {
1435 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1436 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1437 } else {
1438 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1439 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1440 }
1441 break;
1442 }
1443
1444 case Primitive::kPrimChar: {
1445 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1446 Register out = locations->Out().AsArm().AsCoreRegister();
1447 if (index.IsConstant()) {
1448 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1449 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1450 } else {
1451 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1452 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1453 }
1454 break;
1455 }
1456
1457 case Primitive::kPrimInt:
1458 case Primitive::kPrimNot: {
1459 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1460 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1461 Register out = locations->Out().AsArm().AsCoreRegister();
1462 if (index.IsConstant()) {
1463 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1464 __ LoadFromOffset(kLoadWord, out, obj, offset);
1465 } else {
1466 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1467 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1468 }
1469 break;
1470 }
1471
1472 case Primitive::kPrimLong: {
1473 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1474 ArmManagedRegister out = locations->Out().AsArm();
1475 if (index.IsConstant()) {
1476 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1477 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
1478 } else {
1479 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1480 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
1481 }
1482 break;
1483 }
1484
1485 case Primitive::kPrimFloat:
1486 case Primitive::kPrimDouble:
1487 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1488
1489 case Primitive::kPrimVoid:
1490 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1491 }
1492}
1493
1494void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001495 Primitive::Type value_type = instruction->GetComponentType();
1496 bool is_object = value_type == Primitive::kPrimNot;
1497 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1498 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1499 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001500 InvokeRuntimeCallingConvention calling_convention;
1501 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
1502 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
1503 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001504 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001505 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1506 locations->SetInAt(
1507 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1508 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001509 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001510}
1511
1512void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1513 LocationSummary* locations = instruction->GetLocations();
1514 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1515 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001516 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001517
1518 switch (value_type) {
1519 case Primitive::kPrimBoolean:
1520 case Primitive::kPrimByte: {
1521 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1522 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1523 if (index.IsConstant()) {
1524 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1525 __ StoreToOffset(kStoreByte, value, obj, offset);
1526 } else {
1527 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
1528 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1529 }
1530 break;
1531 }
1532
1533 case Primitive::kPrimShort:
1534 case Primitive::kPrimChar: {
1535 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1536 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1537 if (index.IsConstant()) {
1538 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1539 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1540 } else {
1541 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
1542 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1543 }
1544 break;
1545 }
1546
1547 case Primitive::kPrimInt: {
1548 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1549 Register value = locations->InAt(2).AsArm().AsCoreRegister();
1550 if (index.IsConstant()) {
1551 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1552 __ StoreToOffset(kStoreWord, value, obj, offset);
1553 } else {
1554 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
1555 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1556 }
1557 break;
1558 }
1559
1560 case Primitive::kPrimNot: {
1561 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1562 __ ldr(LR, Address(TR, offset));
1563 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001564 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001565 DCHECK(!codegen_->IsLeafMethod());
1566 break;
1567 }
1568
1569 case Primitive::kPrimLong: {
1570 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1571 ArmManagedRegister value = locations->InAt(2).AsArm();
1572 if (index.IsConstant()) {
1573 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1574 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
1575 } else {
1576 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
1577 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
1578 }
1579 break;
1580 }
1581
1582 case Primitive::kPrimFloat:
1583 case Primitive::kPrimDouble:
1584 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1585
1586 case Primitive::kPrimVoid:
1587 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1588 }
1589}
1590
1591void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001592 LocationSummary* locations =
1593 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001594 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001595 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001596}
1597
1598void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1599 LocationSummary* locations = instruction->GetLocations();
1600 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1601 Register obj = locations->InAt(0).AsArm().AsCoreRegister();
1602 Register out = locations->Out().AsArm().AsCoreRegister();
1603 __ LoadFromOffset(kLoadWord, out, obj, offset);
1604}
1605
1606void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001607 LocationSummary* locations =
1608 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001609 locations->SetInAt(0, Location::RequiresRegister());
1610 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001611 if (instruction->HasUses()) {
1612 locations->SetOut(Location::SameAsFirstInput());
1613 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001614}
1615
1616void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1617 LocationSummary* locations = instruction->GetLocations();
1618 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001619 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001620 codegen_->AddSlowPath(slow_path);
1621
1622 Register index = locations->InAt(0).AsArm().AsCoreRegister();
1623 Register length = locations->InAt(1).AsArm().AsCoreRegister();
1624
1625 __ cmp(index, ShifterOperand(length));
1626 __ b(slow_path->GetEntryLabel(), CS);
1627}
1628
1629void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1630 Label is_null;
1631 __ CompareAndBranchIfZero(value, &is_null);
1632 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1633 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1634 __ strb(card, Address(card, temp));
1635 __ Bind(&is_null);
1636}
1637
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001638void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1639 temp->SetLocations(nullptr);
1640}
1641
1642void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1643 // Nothing to do, this is driven by the code generator.
1644}
1645
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001646void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001647 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001648}
1649
1650void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001651 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1652}
1653
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001654void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1655 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1656}
1657
1658void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001659 HBasicBlock* block = instruction->GetBlock();
1660 if (block->GetLoopInformation() != nullptr) {
1661 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1662 // The back edge will generate the suspend check.
1663 return;
1664 }
1665 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1666 // The goto will generate the suspend check.
1667 return;
1668 }
1669 GenerateSuspendCheck(instruction, nullptr);
1670}
1671
1672void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1673 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001674 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001675 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001676 codegen_->AddSlowPath(slow_path);
1677
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001678 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001679 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001680 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001681 __ Bind(slow_path->GetReturnLabel());
1682 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001683 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001684 __ b(slow_path->GetEntryLabel());
1685 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001686}
1687
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001688ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1689 return codegen_->GetAssembler();
1690}
1691
1692void ParallelMoveResolverARM::EmitMove(size_t index) {
1693 MoveOperands* move = moves_.Get(index);
1694 Location source = move->GetSource();
1695 Location destination = move->GetDestination();
1696
1697 if (source.IsRegister()) {
1698 if (destination.IsRegister()) {
1699 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
1700 } else {
1701 DCHECK(destination.IsStackSlot());
1702 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
1703 SP, destination.GetStackIndex());
1704 }
1705 } else if (source.IsStackSlot()) {
1706 if (destination.IsRegister()) {
1707 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
1708 SP, source.GetStackIndex());
1709 } else {
1710 DCHECK(destination.IsStackSlot());
1711 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1712 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1713 }
1714 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001715 DCHECK(source.IsConstant());
1716 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1717 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1718 if (destination.IsRegister()) {
1719 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
1720 } else {
1721 DCHECK(destination.IsStackSlot());
1722 __ LoadImmediate(IP, value);
1723 __ str(IP, Address(SP, destination.GetStackIndex()));
1724 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001725 }
1726}
1727
1728void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1729 __ Mov(IP, reg);
1730 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1731 __ StoreToOffset(kStoreWord, IP, SP, mem);
1732}
1733
1734void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1735 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1736 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1737 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1738 SP, mem1 + stack_offset);
1739 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1740 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1741 SP, mem2 + stack_offset);
1742 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1743}
1744
1745void ParallelMoveResolverARM::EmitSwap(size_t index) {
1746 MoveOperands* move = moves_.Get(index);
1747 Location source = move->GetSource();
1748 Location destination = move->GetDestination();
1749
1750 if (source.IsRegister() && destination.IsRegister()) {
1751 DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
1752 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
1753 __ Mov(IP, source.AsArm().AsCoreRegister());
1754 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
1755 __ Mov(destination.AsArm().AsCoreRegister(), IP);
1756 } else if (source.IsRegister() && destination.IsStackSlot()) {
1757 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
1758 } else if (source.IsStackSlot() && destination.IsRegister()) {
1759 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
1760 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1761 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1762 } else {
1763 LOG(FATAL) << "Unimplemented";
1764 }
1765}
1766
1767void ParallelMoveResolverARM::SpillScratch(int reg) {
1768 __ Push(static_cast<Register>(reg));
1769}
1770
1771void ParallelMoveResolverARM::RestoreScratch(int reg) {
1772 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001773}
1774
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001775} // namespace arm
1776} // namespace art