blob: d555a0d55314898c1cedc4e50fb0a8a099782d32 [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"
Ian Rogers7e70b002014-10-08 11:47:24 -070021#include "mirror/array-inl.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000022#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
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032namespace arm {
33
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010034static SRegister FromDToLowS(DRegister reg) {
35 return static_cast<SRegister>(reg * 2);
36}
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 constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
44static constexpr size_t kRuntimeParameterCoreRegistersLength =
45 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010046static constexpr DRegister kRuntimeParameterFpuRegisters[] = { };
47static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010048
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049class InvokeRuntimeCallingConvention : public CallingConvention<Register, DRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050 public:
51 InvokeRuntimeCallingConvention()
52 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053 kRuntimeParameterCoreRegistersLength,
54 kRuntimeParameterFpuRegisters,
55 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056
57 private:
58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
59};
60
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
62
63class NullCheckSlowPathARM : public SlowPathCode {
64 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010065 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066
67 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
68 __ Bind(GetEntryLabel());
69 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
70 __ ldr(LR, Address(TR, offset));
71 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +010072 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 }
74
75 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
78};
79
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010080class StackOverflowCheckSlowPathARM : public SlowPathCode {
81 public:
82 StackOverflowCheckSlowPathARM() {}
83
84 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
85 __ Bind(GetEntryLabel());
86 __ LoadFromOffset(kLoadWord, PC, TR,
87 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
88 }
89
90 private:
91 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
92};
93
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000094class SuspendCheckSlowPathARM : public SlowPathCode {
95 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +010096 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
97 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000098
99 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
100 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100101 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000102 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
103 __ ldr(LR, Address(TR, offset));
104 __ blx(LR);
105 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100106 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100107 if (successor_ == nullptr) {
108 __ b(GetReturnLabel());
109 } else {
110 __ b(codegen->GetLabelOf(successor_));
111 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000112 }
113
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100114 Label* GetReturnLabel() {
115 DCHECK(successor_ == nullptr);
116 return &return_label_;
117 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118
119 private:
120 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 // If not null, the block to branch to after the suspend check.
122 HBasicBlock* const successor_;
123
124 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125 Label return_label_;
126
127 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
128};
129
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100130class BoundsCheckSlowPathARM : public SlowPathCode {
131 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100132 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
133 Location index_location,
134 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100135 : instruction_(instruction),
136 index_location_(index_location),
137 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138
139 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
140 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
141 __ Bind(GetEntryLabel());
142 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100143 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
144 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100145 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
146 __ ldr(LR, Address(TR, offset));
147 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100148 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100149 }
150
151 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100153 const Location index_location_;
154 const Location length_location_;
155
156 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
157};
158
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100159#undef __
160#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700161
162inline Condition ARMCondition(IfCondition cond) {
163 switch (cond) {
164 case kCondEQ: return EQ;
165 case kCondNE: return NE;
166 case kCondLT: return LT;
167 case kCondLE: return LE;
168 case kCondGT: return GT;
169 case kCondGE: return GE;
170 default:
171 LOG(FATAL) << "Unknown if condition";
172 }
173 return EQ; // Unreachable.
174}
175
176inline Condition ARMOppositeCondition(IfCondition cond) {
177 switch (cond) {
178 case kCondEQ: return NE;
179 case kCondNE: return EQ;
180 case kCondLT: return GE;
181 case kCondLE: return GT;
182 case kCondGT: return LE;
183 case kCondGE: return LT;
184 default:
185 LOG(FATAL) << "Unknown if condition";
186 }
187 return EQ; // Unreachable.
188}
189
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100190void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
191 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
192}
193
194void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
195 stream << ArmManagedRegister::FromDRegister(DRegister(reg));
196}
197
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100198void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
199 __ str(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
200}
201
202void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
203 __ ldr(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex()));
204}
205
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100206CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
207 : CodeGenerator(graph, kNumberOfRegIds),
208 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100209 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100210 move_resolver_(graph->GetArena(), this),
211 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100212
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100213size_t CodeGeneratorARM::FrameEntrySpillSize() const {
214 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
215}
216
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100217static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
218 return blocked_registers + kNumberOfAllocIds;
219}
220
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100221static bool* GetBlockedDRegisters(bool* blocked_registers) {
222 return blocked_registers + kNumberOfCoreRegisters + kNumberOfSRegisters;
223}
224
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100225Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
226 bool* blocked_registers) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100227 switch (type) {
228 case Primitive::kPrimLong: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100229 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
230 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100231 ArmManagedRegister pair =
232 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
233 blocked_registers[pair.AsRegisterPairLow()] = true;
234 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100235 // Block all other register pairs that share a register with `pair`.
236 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
237 ArmManagedRegister current =
238 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
239 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
240 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
241 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
242 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
243 blocked_register_pairs[i] = true;
244 }
245 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100246 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100247 }
248
249 case Primitive::kPrimByte:
250 case Primitive::kPrimBoolean:
251 case Primitive::kPrimChar:
252 case Primitive::kPrimShort:
253 case Primitive::kPrimInt:
254 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100255 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
256 // Block all register pairs that contain `reg`.
257 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
258 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
259 ArmManagedRegister current =
260 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
261 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
262 blocked_register_pairs[i] = true;
263 }
264 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100265 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100266 }
267
268 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100269 case Primitive::kPrimDouble: {
270 int reg = AllocateFreeRegisterInternal(GetBlockedDRegisters(blocked_registers), kNumberOfDRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100271 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100272 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100273
274 case Primitive::kPrimVoid:
275 LOG(FATAL) << "Unreachable type " << type;
276 }
277
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100278 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100279}
280
281void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
282 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100283 bool* blocked_fpu_registers = GetBlockedDRegisters(blocked_registers);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100284
285 // Don't allocate the dalvik style register pair passing.
286 blocked_register_pairs[R1_R2] = true;
287
288 // Stack register, LR and PC are always reserved.
289 blocked_registers[SP] = true;
290 blocked_registers[LR] = true;
291 blocked_registers[PC] = true;
292
293 // Reserve R4 for suspend check.
294 blocked_registers[R4] = true;
295 blocked_register_pairs[R4_R5] = true;
296
297 // Reserve thread register.
298 blocked_registers[TR] = true;
299
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100300 // Reserve temp register.
301 blocked_registers[IP] = true;
302
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100303 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100304 // We always save and restore R6 and R7 to make sure we can use three
305 // register pairs for long operations.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100306 blocked_registers[R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100307 blocked_registers[R8] = true;
308 blocked_registers[R10] = true;
309 blocked_registers[R11] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100310
311 blocked_fpu_registers[D8] = true;
312 blocked_fpu_registers[D9] = true;
313 blocked_fpu_registers[D10] = true;
314 blocked_fpu_registers[D11] = true;
315 blocked_fpu_registers[D12] = true;
316 blocked_fpu_registers[D13] = true;
317 blocked_fpu_registers[D14] = true;
318 blocked_fpu_registers[D15] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100319}
320
321size_t CodeGeneratorARM::GetNumberOfRegisters() const {
322 return kNumberOfRegIds;
323}
324
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100325InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
326 : HGraphVisitor(graph),
327 assembler_(codegen->GetAssembler()),
328 codegen_(codegen) {}
329
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000330void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700331 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100332 if (!skip_overflow_check) {
333 if (kExplicitStackOverflowCheck) {
334 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
335 AddSlowPath(slow_path);
336
337 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
338 __ cmp(SP, ShifterOperand(IP));
339 __ b(slow_path->GetEntryLabel(), CC);
340 } else {
341 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
342 __ ldr(IP, Address(IP, 0));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100343 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100344 }
345 }
346
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100347 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
348 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000349
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100350 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100351 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000352 __ str(R0, Address(SP, 0));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000353}
354
355void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100356 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100357 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000358}
359
360void CodeGeneratorARM::Bind(Label* label) {
361 __ Bind(label);
362}
363
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100364Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
365 switch (load->GetType()) {
366 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100367 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100368 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
369 break;
370
371 case Primitive::kPrimInt:
372 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100373 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100374 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100375
376 case Primitive::kPrimBoolean:
377 case Primitive::kPrimByte:
378 case Primitive::kPrimChar:
379 case Primitive::kPrimShort:
380 case Primitive::kPrimVoid:
381 LOG(FATAL) << "Unexpected type " << load->GetType();
382 }
383
384 LOG(FATAL) << "Unreachable";
385 return Location();
386}
387
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100388Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
389 switch (type) {
390 case Primitive::kPrimBoolean:
391 case Primitive::kPrimByte:
392 case Primitive::kPrimChar:
393 case Primitive::kPrimShort:
394 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100395 case Primitive::kPrimFloat:
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100396 case Primitive::kPrimNot: {
397 uint32_t index = gp_index_++;
398 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100399 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100400 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100401 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100402 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100403 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100404
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100405 case Primitive::kPrimLong:
406 case Primitive::kPrimDouble: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100407 uint32_t index = gp_index_;
408 gp_index_ += 2;
409 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100410 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
411 calling_convention.GetRegisterPairAt(index));
412 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100413 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
414 return Location::QuickParameter(index);
415 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100416 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100417 }
418 }
419
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100420 case Primitive::kPrimVoid:
421 LOG(FATAL) << "Unexpected parameter type " << type;
422 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100423 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100424 return Location();
425}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100426
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100427void CodeGeneratorARM::Move32(Location destination, Location source) {
428 if (source.Equals(destination)) {
429 return;
430 }
431 if (destination.IsRegister()) {
432 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100433 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100434 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100435 __ vmovrs(destination.As<Register>(), FromDToLowS(source.As<DRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100436 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100437 __ ldr(destination.As<Register>(), Address(SP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100438 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100439 } else if (destination.IsFpuRegister()) {
440 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100441 __ vmovsr(FromDToLowS(destination.As<DRegister>()), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100442 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100443 __ vmovs(FromDToLowS(destination.As<DRegister>()), FromDToLowS(source.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100444 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100445 __ vldrs(FromDToLowS(destination.As<DRegister>()), Address(SP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100446 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100447 } else {
448 DCHECK(destination.IsStackSlot());
449 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100450 __ str(source.As<Register>(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100451 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100452 __ vstrs(FromDToLowS(source.As<DRegister>()), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100453 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100454 DCHECK(source.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100455 __ ldr(IP, Address(SP, source.GetStackIndex()));
456 __ str(IP, Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100457 }
458 }
459}
460
461void CodeGeneratorARM::Move64(Location destination, Location source) {
462 if (source.Equals(destination)) {
463 return;
464 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100465 if (destination.IsRegisterPair()) {
466 if (source.IsRegisterPair()) {
467 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
468 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100469 } else if (source.IsFpuRegister()) {
470 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100471 } else if (source.IsQuickParameter()) {
472 uint32_t argument_index = source.GetQuickParameterIndex();
473 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100474 __ Mov(destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100475 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100476 __ ldr(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100477 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100478 } else {
479 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100480 if (destination.AsRegisterPairLow<Register>() == R1) {
481 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100482 __ ldr(R1, Address(SP, source.GetStackIndex()));
483 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
484 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100485 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100486 SP, source.GetStackIndex());
487 }
488 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100489 } else if (destination.IsFpuRegister()) {
490 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100491 __ vldrd(destination.As<DRegister>(), Address(SP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100492 } else {
493 LOG(FATAL) << "Unimplemented";
494 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100495 } else if (destination.IsQuickParameter()) {
496 InvokeDexCallingConvention calling_convention;
497 uint32_t argument_index = destination.GetQuickParameterIndex();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100498 if (source.IsRegisterPair()) {
499 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsRegisterPairLow<Register>());
500 __ str(source.AsRegisterPairHigh<Register>(),
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100501 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100502 } else if (source.IsFpuRegister()) {
503 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100504 } else {
505 DCHECK(source.IsDoubleStackSlot());
506 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100507 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
508 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100509 }
510 } else {
511 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100512 if (source.IsRegisterPair()) {
513 if (source.AsRegisterPairLow<Register>() == R1) {
514 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100515 __ str(R1, Address(SP, destination.GetStackIndex()));
516 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
517 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100518 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100519 SP, destination.GetStackIndex());
520 }
521 } else if (source.IsQuickParameter()) {
522 InvokeDexCallingConvention calling_convention;
523 uint32_t argument_index = source.GetQuickParameterIndex();
524 __ str(calling_convention.GetRegisterAt(argument_index),
525 Address(SP, destination.GetStackIndex()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100526 __ ldr(R0,
527 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
528 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100529 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100530 __ vstrd(source.As<DRegister>(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100531 } else {
532 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100533 __ ldr(IP, Address(SP, source.GetStackIndex()));
534 __ str(IP, Address(SP, destination.GetStackIndex()));
535 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
536 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100537 }
538 }
539}
540
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100541void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100542 LocationSummary* locations = instruction->GetLocations();
543 if (locations != nullptr && locations->Out().Equals(location)) {
544 return;
545 }
546
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100547 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100548 int32_t value = instruction->AsIntConstant()->GetValue();
549 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100550 __ LoadImmediate(location.As<Register>(), value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100551 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100552 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100553 __ LoadImmediate(IP, value);
554 __ str(IP, Address(SP, location.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100555 }
556 } else if (instruction->AsLongConstant() != nullptr) {
557 int64_t value = instruction->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100558 if (location.IsRegisterPair()) {
559 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
560 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100561 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100562 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100563 __ LoadImmediate(IP, Low32Bits(value));
564 __ str(IP, Address(SP, location.GetStackIndex()));
565 __ LoadImmediate(IP, High32Bits(value));
566 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100567 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100568 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100569 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
570 switch (instruction->GetType()) {
571 case Primitive::kPrimBoolean:
572 case Primitive::kPrimByte:
573 case Primitive::kPrimChar:
574 case Primitive::kPrimShort:
575 case Primitive::kPrimInt:
576 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100577 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100578 Move32(location, Location::StackSlot(stack_slot));
579 break;
580
581 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100582 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100583 Move64(location, Location::DoubleStackSlot(stack_slot));
584 break;
585
586 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100587 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100588 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000589 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100590 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100591 switch (instruction->GetType()) {
592 case Primitive::kPrimBoolean:
593 case Primitive::kPrimByte:
594 case Primitive::kPrimChar:
595 case Primitive::kPrimShort:
596 case Primitive::kPrimNot:
597 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100598 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100599 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100600 break;
601
602 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100603 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100604 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100605 break;
606
607 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100608 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100609 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000610 }
611}
612
613void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000614 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000615}
616
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000617void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000618 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100619 DCHECK(!successor->IsExitBlock());
620
621 HBasicBlock* block = got->GetBlock();
622 HInstruction* previous = got->GetPrevious();
623
624 HLoopInformation* info = block->GetLoopInformation();
625 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
626 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
627 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
628 return;
629 }
630
631 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
632 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
633 }
634 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000635 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000636 }
637}
638
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000639void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000640 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000641}
642
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000643void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000644 if (kIsDebugBuild) {
645 __ Comment("Unreachable");
646 __ bkpt(0);
647 }
648}
649
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000650void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100651 LocationSummary* locations =
652 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100653 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100654 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100655 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100656 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000657}
658
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000659void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700660 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100661 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700662 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100663 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100664 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
Dave Allison20dfc792014-06-16 20:44:29 -0700665 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100666 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700667 } else {
668 // Condition has not been materialized, use its inputs as the comparison and its
669 // condition as the branch condition.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100670 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100671 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100672 __ cmp(locations->InAt(0).As<Register>(),
673 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100674 } else {
675 DCHECK(locations->InAt(1).IsConstant());
676 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
677 ShifterOperand operand;
678 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100679 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100680 } else {
681 Register temp = IP;
682 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100683 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100684 }
685 }
Dave Allison20dfc792014-06-16 20:44:29 -0700686 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100687 ARMCondition(cond->AsCondition()->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700688 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100689
Dave Allison20dfc792014-06-16 20:44:29 -0700690 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
691 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000692 }
693}
694
Dave Allison20dfc792014-06-16 20:44:29 -0700695
696void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100697 LocationSummary* locations =
698 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100699 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
700 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100701 if (comp->NeedsMaterialization()) {
702 locations->SetOut(Location::RequiresRegister());
703 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000704}
705
Dave Allison20dfc792014-06-16 20:44:29 -0700706void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100707 if (!comp->NeedsMaterialization()) return;
708
709 LocationSummary* locations = comp->GetLocations();
710 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100711 __ cmp(locations->InAt(0).As<Register>(),
712 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100713 } else {
714 DCHECK(locations->InAt(1).IsConstant());
715 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
716 ShifterOperand operand;
717 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100718 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100719 } else {
720 Register temp = IP;
721 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100722 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100723 }
Dave Allison20dfc792014-06-16 20:44:29 -0700724 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100725 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100726 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100727 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100728 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100729 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700730}
731
732void LocationsBuilderARM::VisitEqual(HEqual* comp) {
733 VisitCondition(comp);
734}
735
736void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
737 VisitCondition(comp);
738}
739
740void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
741 VisitCondition(comp);
742}
743
744void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
745 VisitCondition(comp);
746}
747
748void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
749 VisitCondition(comp);
750}
751
752void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
753 VisitCondition(comp);
754}
755
756void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
757 VisitCondition(comp);
758}
759
760void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
761 VisitCondition(comp);
762}
763
764void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
765 VisitCondition(comp);
766}
767
768void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
769 VisitCondition(comp);
770}
771
772void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
773 VisitCondition(comp);
774}
775
776void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
777 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000778}
779
780void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000781 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000782}
783
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000784void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
785 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000786}
787
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000788void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100789 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000790}
791
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000792void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100793 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000794}
795
796void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100797 LocationSummary* locations =
798 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100799 switch (store->InputAt(1)->GetType()) {
800 case Primitive::kPrimBoolean:
801 case Primitive::kPrimByte:
802 case Primitive::kPrimChar:
803 case Primitive::kPrimShort:
804 case Primitive::kPrimInt:
805 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100806 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100807 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
808 break;
809
810 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100811 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100812 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
813 break;
814
815 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100816 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100817 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000818}
819
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000820void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000821}
822
823void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100824 LocationSummary* locations =
825 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100826 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000827}
828
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000829void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000830}
831
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100832void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100833 LocationSummary* locations =
834 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100835 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100836}
837
838void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
839 // Will be generated at use site.
840}
841
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000842void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000843 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000844}
845
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000846void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
847 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000848}
849
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000850void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100851 LocationSummary* locations =
852 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100853 switch (ret->InputAt(0)->GetType()) {
854 case Primitive::kPrimBoolean:
855 case Primitive::kPrimByte:
856 case Primitive::kPrimChar:
857 case Primitive::kPrimShort:
858 case Primitive::kPrimInt:
859 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100860 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100861 locations->SetInAt(0, Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100862 break;
863
864 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100865 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100866 locations->SetInAt(0, Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100867 break;
868
869 default:
870 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
871 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000872}
873
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000874void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100875 if (kIsDebugBuild) {
876 switch (ret->InputAt(0)->GetType()) {
877 case Primitive::kPrimBoolean:
878 case Primitive::kPrimByte:
879 case Primitive::kPrimChar:
880 case Primitive::kPrimShort:
881 case Primitive::kPrimInt:
882 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100883 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100884 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100885 break;
886
887 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100888 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100889 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0);
890 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100891 break;
892
893 default:
894 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
895 }
896 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000897 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000898}
899
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000900void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100901 HandleInvoke(invoke);
902}
903
904void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
905 __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
906}
907
908void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100909 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100910 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
911 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
912 invoke->GetIndexInDexCache() * kArmWordSize;
913
914 // TODO: Implement all kinds of calls:
915 // 1) boot -> boot
916 // 2) app -> boot
917 // 3) app -> app
918 //
919 // Currently we implement the app -> app logic, which looks up in the resolve cache.
920
921 // temp = method;
922 LoadCurrentMethod(temp);
923 // temp = temp->dex_cache_resolved_methods_;
924 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
925 // temp = temp[index_in_cache]
926 __ ldr(temp, Address(temp, index_in_cache));
927 // LR = temp[offset_of_quick_compiled_code]
928 __ ldr(LR, Address(temp,
929 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
930 // LR()
931 __ blx(LR);
932
933 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
934 DCHECK(!codegen_->IsLeafMethod());
935}
936
937void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
938 HandleInvoke(invoke);
939}
940
941void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100942 LocationSummary* locations =
943 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100944 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100945
946 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100947 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100948 HInstruction* input = invoke->InputAt(i);
949 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
950 }
951
952 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100953 case Primitive::kPrimBoolean:
954 case Primitive::kPrimByte:
955 case Primitive::kPrimChar:
956 case Primitive::kPrimShort:
957 case Primitive::kPrimInt:
958 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100959 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100960 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100961 break;
962
963 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100964 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100965 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100966 break;
967
968 case Primitive::kPrimVoid:
969 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100970 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000971}
972
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000973
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100974void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100975 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100976 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
977 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
978 LocationSummary* locations = invoke->GetLocations();
979 Location receiver = locations->InAt(0);
980 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
981 // temp = object->GetClass();
982 if (receiver.IsStackSlot()) {
983 __ ldr(temp, Address(SP, receiver.GetStackIndex()));
984 __ ldr(temp, Address(temp, class_offset));
985 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100986 __ ldr(temp, Address(receiver.As<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100987 }
988 // temp = temp->GetMethodAt(method_offset);
989 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
990 __ ldr(temp, Address(temp, method_offset));
991 // LR = temp->GetEntryPoint();
992 __ ldr(LR, Address(temp, entry_point));
993 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000994 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100995 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100996 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000997}
998
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000999void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001000 LocationSummary* locations =
1001 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001002 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001003 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001004 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001005 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
1006 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1007 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001008 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001009 break;
1010 }
1011
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001012 case Primitive::kPrimFloat:
1013 case Primitive::kPrimDouble: {
1014 locations->SetInAt(0, Location::RequiresFpuRegister());
1015 locations->SetInAt(1, Location::RequiresFpuRegister());
1016 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001017 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001018 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001019
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001020 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001021 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001022 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001023}
1024
1025void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1026 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001027 Location out = locations->Out();
1028 Location first = locations->InAt(0);
1029 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001030 switch (add->GetResultType()) {
1031 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001032 if (second.IsRegister()) {
1033 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001034 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001035 __ AddConstant(out.As<Register>(),
1036 first.As<Register>(),
1037 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001038 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001039 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001040
1041 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001042 __ adds(out.AsRegisterPairLow<Register>(),
1043 first.AsRegisterPairLow<Register>(),
1044 ShifterOperand(second.AsRegisterPairLow<Register>()));
1045 __ adc(out.AsRegisterPairHigh<Register>(),
1046 first.AsRegisterPairHigh<Register>(),
1047 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001048 break;
1049
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001050 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001051 __ vadds(FromDToLowS(out.As<DRegister>()),
1052 FromDToLowS(first.As<DRegister>()),
1053 FromDToLowS(second.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001054 break;
1055
1056 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001057 __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001058 break;
1059
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001060 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001061 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001062 }
1063}
1064
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001065void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001066 LocationSummary* locations =
1067 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001068 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001069 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001070 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001071 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1072 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1073 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001074 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001075 break;
1076 }
1077
1078 case Primitive::kPrimBoolean:
1079 case Primitive::kPrimByte:
1080 case Primitive::kPrimChar:
1081 case Primitive::kPrimShort:
1082 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1083 break;
1084
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001085 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001086 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001087 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001088}
1089
1090void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1091 LocationSummary* locations = sub->GetLocations();
1092 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001093 case Primitive::kPrimInt: {
1094 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001095 __ sub(locations->Out().As<Register>(),
1096 locations->InAt(0).As<Register>(),
1097 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001098 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001099 __ AddConstant(locations->Out().As<Register>(),
1100 locations->InAt(0).As<Register>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001101 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1102 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001103 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001104 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001105
1106 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001107 __ subs(locations->Out().AsRegisterPairLow<Register>(),
1108 locations->InAt(0).AsRegisterPairLow<Register>(),
1109 ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
1110 __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
1111 locations->InAt(0).AsRegisterPairHigh<Register>(),
1112 ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001113 break;
1114
1115 case Primitive::kPrimBoolean:
1116 case Primitive::kPrimByte:
1117 case Primitive::kPrimChar:
1118 case Primitive::kPrimShort:
1119 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1120 break;
1121
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001122 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001123 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001124 }
1125}
1126
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001127void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001128 LocationSummary* locations =
1129 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001130 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001131 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1132 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1133 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001134}
1135
1136void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1137 InvokeRuntimeCallingConvention calling_convention;
1138 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1139 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1140
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001141 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001142 __ ldr(LR, Address(TR, offset));
1143 __ blx(LR);
1144
Nicolas Geoffray39468442014-09-02 15:17:15 +01001145 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001146 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001147}
1148
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001149void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001150 LocationSummary* locations =
1151 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001152 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1153 if (location.IsStackSlot()) {
1154 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1155 } else if (location.IsDoubleStackSlot()) {
1156 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001157 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001158 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001159}
1160
1161void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001162 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001163}
1164
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001165void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001166 LocationSummary* locations =
1167 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001168 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001169 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001170}
1171
1172void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1173 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001174 __ eor(locations->Out().As<Register>(),
1175 locations->InAt(0).As<Register>(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001176}
1177
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001178void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001179 LocationSummary* locations =
1180 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001181 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1182 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001183 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001184}
1185
1186void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1187 Label greater, done;
1188 LocationSummary* locations = compare->GetLocations();
1189 switch (compare->InputAt(0)->GetType()) {
1190 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001191 Register output = locations->Out().As<Register>();
1192 Location left = locations->InAt(0);
1193 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001194 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001195 __ cmp(left.AsRegisterPairHigh<Register>(),
1196 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001197 __ b(&less, LT);
1198 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001199 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1200 // the status flags.
1201 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001202 __ cmp(left.AsRegisterPairLow<Register>(),
1203 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001204 __ b(&done, EQ);
1205 __ b(&less, CC);
1206
1207 __ Bind(&greater);
1208 __ LoadImmediate(output, 1);
1209 __ b(&done);
1210
1211 __ Bind(&less);
1212 __ LoadImmediate(output, -1);
1213
1214 __ Bind(&done);
1215 break;
1216 }
1217 default:
1218 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1219 }
1220}
1221
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001222void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001223 LocationSummary* locations =
1224 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001225 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1226 locations->SetInAt(i, Location::Any());
1227 }
1228 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001229}
1230
1231void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001232 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001233}
1234
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001235void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001236 LocationSummary* locations =
1237 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001238 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1239 bool dies_at_entry = !is_object_type;
1240 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1241 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001242 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001243 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001244 locations->AddTemp(Location::RequiresRegister());
1245 locations->AddTemp(Location::RequiresRegister());
1246 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001247}
1248
1249void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1250 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001251 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001252 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001253 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001254
1255 switch (field_type) {
1256 case Primitive::kPrimBoolean:
1257 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001258 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001259 __ StoreToOffset(kStoreByte, value, obj, offset);
1260 break;
1261 }
1262
1263 case Primitive::kPrimShort:
1264 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001265 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001266 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1267 break;
1268 }
1269
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001270 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001271 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001272 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001273 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001274 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001275 Register temp = locations->GetTemp(0).As<Register>();
1276 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001277 codegen_->MarkGCCard(temp, card, obj, value);
1278 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001279 break;
1280 }
1281
1282 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001283 Location value = locations->InAt(1);
1284 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001285 break;
1286 }
1287
1288 case Primitive::kPrimFloat:
1289 case Primitive::kPrimDouble:
1290 LOG(FATAL) << "Unimplemented register type " << field_type;
1291
1292 case Primitive::kPrimVoid:
1293 LOG(FATAL) << "Unreachable type " << field_type;
1294 }
1295}
1296
1297void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001298 LocationSummary* locations =
1299 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001300 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001301 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001302}
1303
1304void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1305 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001306 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001307 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1308
1309 switch (instruction->GetType()) {
1310 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001311 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001312 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1313 break;
1314 }
1315
1316 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001317 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001318 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1319 break;
1320 }
1321
1322 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001323 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001324 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1325 break;
1326 }
1327
1328 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001329 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001330 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1331 break;
1332 }
1333
1334 case Primitive::kPrimInt:
1335 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001336 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001337 __ LoadFromOffset(kLoadWord, out, obj, offset);
1338 break;
1339 }
1340
1341 case Primitive::kPrimLong: {
1342 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001343 Location out = locations->Out();
1344 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001345 break;
1346 }
1347
1348 case Primitive::kPrimFloat:
1349 case Primitive::kPrimDouble:
1350 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1351
1352 case Primitive::kPrimVoid:
1353 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1354 }
1355}
1356
1357void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001358 LocationSummary* locations =
1359 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001360 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001361 if (instruction->HasUses()) {
1362 locations->SetOut(Location::SameAsFirstInput());
1363 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001364}
1365
1366void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001367 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001368 codegen_->AddSlowPath(slow_path);
1369
1370 LocationSummary* locations = instruction->GetLocations();
1371 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001372
1373 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001374 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001375 __ b(slow_path->GetEntryLabel(), EQ);
1376 } else {
1377 DCHECK(obj.IsConstant()) << obj;
1378 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1379 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001380 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001381}
1382
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001383void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001384 LocationSummary* locations =
1385 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001386 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1387 locations->SetInAt(
1388 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001389 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001390}
1391
1392void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1393 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001394 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001395 Location index = locations->InAt(1);
1396
1397 switch (instruction->GetType()) {
1398 case Primitive::kPrimBoolean: {
1399 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001400 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001401 if (index.IsConstant()) {
1402 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1403 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1404 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001405 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001406 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1407 }
1408 break;
1409 }
1410
1411 case Primitive::kPrimByte: {
1412 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001413 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001414 if (index.IsConstant()) {
1415 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1416 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1417 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001418 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001419 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1420 }
1421 break;
1422 }
1423
1424 case Primitive::kPrimShort: {
1425 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001426 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001427 if (index.IsConstant()) {
1428 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1429 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1430 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001431 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001432 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1433 }
1434 break;
1435 }
1436
1437 case Primitive::kPrimChar: {
1438 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001439 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001440 if (index.IsConstant()) {
1441 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1442 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1443 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001444 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001445 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1446 }
1447 break;
1448 }
1449
1450 case Primitive::kPrimInt:
1451 case Primitive::kPrimNot: {
1452 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1453 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001454 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001455 if (index.IsConstant()) {
1456 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1457 __ LoadFromOffset(kLoadWord, out, obj, offset);
1458 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001459 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001460 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1461 }
1462 break;
1463 }
1464
1465 case Primitive::kPrimLong: {
1466 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001467 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001468 if (index.IsConstant()) {
1469 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001470 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001471 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001472 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1473 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001474 }
1475 break;
1476 }
1477
1478 case Primitive::kPrimFloat:
1479 case Primitive::kPrimDouble:
1480 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1481
1482 case Primitive::kPrimVoid:
1483 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1484 }
1485}
1486
1487void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001488 Primitive::Type value_type = instruction->GetComponentType();
1489 bool is_object = value_type == Primitive::kPrimNot;
1490 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1491 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1492 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001493 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001494 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1495 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1496 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001497 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001498 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1499 locations->SetInAt(
1500 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1501 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001502 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001503}
1504
1505void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1506 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001507 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001508 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001509 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001510
1511 switch (value_type) {
1512 case Primitive::kPrimBoolean:
1513 case Primitive::kPrimByte: {
1514 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001515 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001516 if (index.IsConstant()) {
1517 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1518 __ StoreToOffset(kStoreByte, value, obj, offset);
1519 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001520 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001521 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1522 }
1523 break;
1524 }
1525
1526 case Primitive::kPrimShort:
1527 case Primitive::kPrimChar: {
1528 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001529 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001530 if (index.IsConstant()) {
1531 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1532 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1533 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001534 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001535 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1536 }
1537 break;
1538 }
1539
1540 case Primitive::kPrimInt: {
1541 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001542 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001543 if (index.IsConstant()) {
1544 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1545 __ StoreToOffset(kStoreWord, value, obj, offset);
1546 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001547 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001548 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1549 }
1550 break;
1551 }
1552
1553 case Primitive::kPrimNot: {
1554 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
1555 __ ldr(LR, Address(TR, offset));
1556 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001557 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001558 DCHECK(!codegen_->IsLeafMethod());
1559 break;
1560 }
1561
1562 case Primitive::kPrimLong: {
1563 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001564 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001565 if (index.IsConstant()) {
1566 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001567 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001568 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001569 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1570 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001571 }
1572 break;
1573 }
1574
1575 case Primitive::kPrimFloat:
1576 case Primitive::kPrimDouble:
1577 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1578
1579 case Primitive::kPrimVoid:
1580 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1581 }
1582}
1583
1584void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001585 LocationSummary* locations =
1586 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001587 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001588 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001589}
1590
1591void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1592 LocationSummary* locations = instruction->GetLocations();
1593 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001594 Register obj = locations->InAt(0).As<Register>();
1595 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001596 __ LoadFromOffset(kLoadWord, out, obj, offset);
1597}
1598
1599void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001600 LocationSummary* locations =
1601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001602 locations->SetInAt(0, Location::RequiresRegister());
1603 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001604 if (instruction->HasUses()) {
1605 locations->SetOut(Location::SameAsFirstInput());
1606 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001607}
1608
1609void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1610 LocationSummary* locations = instruction->GetLocations();
1611 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001612 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001613 codegen_->AddSlowPath(slow_path);
1614
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001615 Register index = locations->InAt(0).As<Register>();
1616 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001617
1618 __ cmp(index, ShifterOperand(length));
1619 __ b(slow_path->GetEntryLabel(), CS);
1620}
1621
1622void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1623 Label is_null;
1624 __ CompareAndBranchIfZero(value, &is_null);
1625 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1626 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1627 __ strb(card, Address(card, temp));
1628 __ Bind(&is_null);
1629}
1630
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001631void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1632 temp->SetLocations(nullptr);
1633}
1634
1635void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1636 // Nothing to do, this is driven by the code generator.
1637}
1638
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001639void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001640 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001641}
1642
1643void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001644 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1645}
1646
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001647void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1648 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1649}
1650
1651void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001652 HBasicBlock* block = instruction->GetBlock();
1653 if (block->GetLoopInformation() != nullptr) {
1654 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1655 // The back edge will generate the suspend check.
1656 return;
1657 }
1658 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1659 // The goto will generate the suspend check.
1660 return;
1661 }
1662 GenerateSuspendCheck(instruction, nullptr);
1663}
1664
1665void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1666 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001667 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001668 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001669 codegen_->AddSlowPath(slow_path);
1670
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001671 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001672 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001673 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001674 __ Bind(slow_path->GetReturnLabel());
1675 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001676 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001677 __ b(slow_path->GetEntryLabel());
1678 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001679}
1680
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001681ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1682 return codegen_->GetAssembler();
1683}
1684
1685void ParallelMoveResolverARM::EmitMove(size_t index) {
1686 MoveOperands* move = moves_.Get(index);
1687 Location source = move->GetSource();
1688 Location destination = move->GetDestination();
1689
1690 if (source.IsRegister()) {
1691 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001692 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001693 } else {
1694 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001695 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001696 SP, destination.GetStackIndex());
1697 }
1698 } else if (source.IsStackSlot()) {
1699 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001700 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001701 SP, source.GetStackIndex());
1702 } else {
1703 DCHECK(destination.IsStackSlot());
1704 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1705 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1706 }
1707 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001708 DCHECK(source.IsConstant());
1709 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1710 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1711 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001712 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001713 } else {
1714 DCHECK(destination.IsStackSlot());
1715 __ LoadImmediate(IP, value);
1716 __ str(IP, Address(SP, destination.GetStackIndex()));
1717 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001718 }
1719}
1720
1721void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1722 __ Mov(IP, reg);
1723 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1724 __ StoreToOffset(kStoreWord, IP, SP, mem);
1725}
1726
1727void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1728 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1729 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1730 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1731 SP, mem1 + stack_offset);
1732 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1733 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1734 SP, mem2 + stack_offset);
1735 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1736}
1737
1738void ParallelMoveResolverARM::EmitSwap(size_t index) {
1739 MoveOperands* move = moves_.Get(index);
1740 Location source = move->GetSource();
1741 Location destination = move->GetDestination();
1742
1743 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001744 DCHECK_NE(source.As<Register>(), IP);
1745 DCHECK_NE(destination.As<Register>(), IP);
1746 __ Mov(IP, source.As<Register>());
1747 __ Mov(source.As<Register>(), destination.As<Register>());
1748 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001749 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001750 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001751 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001752 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001753 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1754 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1755 } else {
1756 LOG(FATAL) << "Unimplemented";
1757 }
1758}
1759
1760void ParallelMoveResolverARM::SpillScratch(int reg) {
1761 __ Push(static_cast<Register>(reg));
1762}
1763
1764void ParallelMoveResolverARM::RestoreScratch(int reg) {
1765 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001766}
1767
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001768} // namespace arm
1769} // namespace art