blob: 0e6b2031bb4e7e8b0bef4972380997aaaa09108d [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();
Nicolas Geoffray360231a2014-10-08 21:07:48 +010070 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071 __ 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();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100103 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000104 __ 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();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100146 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100147 __ 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) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100199 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100200}
201
202void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100203 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100204}
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)));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100342 __ LoadFromOffset(kLoadWord, IP, 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 Geoffray360231a2014-10-08 21:07:48 +0100352 __ StoreToOffset(kStoreWord, R0, 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 Geoffray360231a2014-10-08 21:07:48 +0100437 __ LoadFromOffset(kLoadWord, destination.As<Register>(), 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 Geoffray360231a2014-10-08 21:07:48 +0100450 __ StoreToOffset(kStoreWord, source.As<Register>(), 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 Geoffray360231a2014-10-08 21:07:48 +0100455 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
456 __ StoreToOffset(kStoreWord, IP, 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 Geoffray360231a2014-10-08 21:07:48 +0100476 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(),
477 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 Geoffray360231a2014-10-08 21:07:48 +0100482 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
483 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100484 } 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()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100499 __ Mov(calling_convention.GetRegisterAt(argument_index),
500 source.AsRegisterPairLow<Register>());
501 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(),
502 SP, calling_convention.GetStackOffsetOf(argument_index + 1));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100503 } else if (source.IsFpuRegister()) {
504 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100505 } else {
506 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100507 __ LoadFromOffset(kLoadWord, calling_convention.GetRegisterAt(argument_index), SP, source.GetStackIndex());
508 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize));
509 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(argument_index + 1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100510 }
511 } else {
512 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100513 if (source.IsRegisterPair()) {
514 if (source.AsRegisterPairLow<Register>() == R1) {
515 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100516 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
517 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100518 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100519 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100520 SP, destination.GetStackIndex());
521 }
522 } else if (source.IsQuickParameter()) {
523 InvokeDexCallingConvention calling_convention;
524 uint32_t argument_index = source.GetQuickParameterIndex();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100525 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(argument_index),
526 SP, destination.GetStackIndex());
527 __ LoadFromOffset(kLoadWord, R0,
528 SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize());
529 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100530 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100531 __ vstrd(source.As<DRegister>(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100532 } else {
533 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100534 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
535 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
536 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
537 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100538 }
539 }
540}
541
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100542void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100543 LocationSummary* locations = instruction->GetLocations();
544 if (locations != nullptr && locations->Out().Equals(location)) {
545 return;
546 }
547
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100548 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100549 int32_t value = instruction->AsIntConstant()->GetValue();
550 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100551 __ LoadImmediate(location.As<Register>(), value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100552 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100553 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100554 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100555 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100556 }
557 } else if (instruction->AsLongConstant() != nullptr) {
558 int64_t value = instruction->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100559 if (location.IsRegisterPair()) {
560 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
561 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100562 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100563 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100564 __ LoadImmediate(IP, Low32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100565 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100566 __ LoadImmediate(IP, High32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100567 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100568 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100569 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100570 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
571 switch (instruction->GetType()) {
572 case Primitive::kPrimBoolean:
573 case Primitive::kPrimByte:
574 case Primitive::kPrimChar:
575 case Primitive::kPrimShort:
576 case Primitive::kPrimInt:
577 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100579 Move32(location, Location::StackSlot(stack_slot));
580 break;
581
582 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100583 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100584 Move64(location, Location::DoubleStackSlot(stack_slot));
585 break;
586
587 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100589 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000590 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100591 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100592 switch (instruction->GetType()) {
593 case Primitive::kPrimBoolean:
594 case Primitive::kPrimByte:
595 case Primitive::kPrimChar:
596 case Primitive::kPrimShort:
597 case Primitive::kPrimNot:
598 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100599 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100600 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100601 break;
602
603 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100604 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100605 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100606 break;
607
608 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100609 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100610 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000611 }
612}
613
614void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000615 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000616}
617
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000618void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000619 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100620 DCHECK(!successor->IsExitBlock());
621
622 HBasicBlock* block = got->GetBlock();
623 HInstruction* previous = got->GetPrevious();
624
625 HLoopInformation* info = block->GetLoopInformation();
626 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
627 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
628 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
629 return;
630 }
631
632 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
633 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
634 }
635 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000636 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000637 }
638}
639
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000640void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000641 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000642}
643
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000644void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000645 if (kIsDebugBuild) {
646 __ Comment("Unreachable");
647 __ bkpt(0);
648 }
649}
650
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000651void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100652 LocationSummary* locations =
653 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100654 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100655 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100656 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100657 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000658}
659
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000660void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700661 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700663 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100664 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100665 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
Dave Allison20dfc792014-06-16 20:44:29 -0700666 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100667 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700668 } else {
669 // Condition has not been materialized, use its inputs as the comparison and its
670 // condition as the branch condition.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100671 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100672 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100673 __ cmp(locations->InAt(0).As<Register>(),
674 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100675 } else {
676 DCHECK(locations->InAt(1).IsConstant());
677 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
678 ShifterOperand operand;
679 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100680 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100681 } else {
682 Register temp = IP;
683 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100684 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100685 }
686 }
Dave Allison20dfc792014-06-16 20:44:29 -0700687 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100688 ARMCondition(cond->AsCondition()->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700689 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100690
Dave Allison20dfc792014-06-16 20:44:29 -0700691 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
692 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000693 }
694}
695
Dave Allison20dfc792014-06-16 20:44:29 -0700696
697void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100698 LocationSummary* locations =
699 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100700 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
701 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100702 if (comp->NeedsMaterialization()) {
703 locations->SetOut(Location::RequiresRegister());
704 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000705}
706
Dave Allison20dfc792014-06-16 20:44:29 -0700707void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100708 if (!comp->NeedsMaterialization()) return;
709
710 LocationSummary* locations = comp->GetLocations();
711 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100712 __ cmp(locations->InAt(0).As<Register>(),
713 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100714 } else {
715 DCHECK(locations->InAt(1).IsConstant());
716 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
717 ShifterOperand operand;
718 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100719 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100720 } else {
721 Register temp = IP;
722 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100723 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100724 }
Dave Allison20dfc792014-06-16 20:44:29 -0700725 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100726 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100727 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100728 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100729 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100730 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700731}
732
733void LocationsBuilderARM::VisitEqual(HEqual* comp) {
734 VisitCondition(comp);
735}
736
737void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
738 VisitCondition(comp);
739}
740
741void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
742 VisitCondition(comp);
743}
744
745void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
746 VisitCondition(comp);
747}
748
749void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
750 VisitCondition(comp);
751}
752
753void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
754 VisitCondition(comp);
755}
756
757void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
758 VisitCondition(comp);
759}
760
761void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
762 VisitCondition(comp);
763}
764
765void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
766 VisitCondition(comp);
767}
768
769void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
770 VisitCondition(comp);
771}
772
773void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
774 VisitCondition(comp);
775}
776
777void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
778 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000779}
780
781void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000782 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000783}
784
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000785void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
786 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000787}
788
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000789void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100790 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000791}
792
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000793void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100794 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000795}
796
797void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100798 LocationSummary* locations =
799 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100800 switch (store->InputAt(1)->GetType()) {
801 case Primitive::kPrimBoolean:
802 case Primitive::kPrimByte:
803 case Primitive::kPrimChar:
804 case Primitive::kPrimShort:
805 case Primitive::kPrimInt:
806 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100807 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
809 break;
810
811 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100812 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
814 break;
815
816 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100817 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100818 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000819}
820
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000821void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000822}
823
824void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100825 LocationSummary* locations =
826 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100827 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000828}
829
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000830void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000831}
832
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100834 LocationSummary* locations =
835 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100836 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100837}
838
839void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
840 // Will be generated at use site.
841}
842
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000843void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000844 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000845}
846
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000847void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
848 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000849}
850
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000851void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100852 LocationSummary* locations =
853 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100854 switch (ret->InputAt(0)->GetType()) {
855 case Primitive::kPrimBoolean:
856 case Primitive::kPrimByte:
857 case Primitive::kPrimChar:
858 case Primitive::kPrimShort:
859 case Primitive::kPrimInt:
860 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100861 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100862 locations->SetInAt(0, Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863 break;
864
865 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100867 locations->SetInAt(0, Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100868 break;
869
870 default:
871 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
872 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000873}
874
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000875void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100876 if (kIsDebugBuild) {
877 switch (ret->InputAt(0)->GetType()) {
878 case Primitive::kPrimBoolean:
879 case Primitive::kPrimByte:
880 case Primitive::kPrimChar:
881 case Primitive::kPrimShort:
882 case Primitive::kPrimInt:
883 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100884 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100885 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 break;
887
888 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100889 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100890 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0);
891 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100892 break;
893
894 default:
895 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
896 }
897 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000898 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000899}
900
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000901void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100902 HandleInvoke(invoke);
903}
904
905void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100906 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100907}
908
909void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100910 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100911 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
912 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
913 invoke->GetIndexInDexCache() * kArmWordSize;
914
915 // TODO: Implement all kinds of calls:
916 // 1) boot -> boot
917 // 2) app -> boot
918 // 3) app -> app
919 //
920 // Currently we implement the app -> app logic, which looks up in the resolve cache.
921
922 // temp = method;
923 LoadCurrentMethod(temp);
924 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100925 __ LoadFromOffset(kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100926 // temp = temp[index_in_cache]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100927 __ LoadFromOffset(kLoadWord, temp, temp, index_in_cache);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100928 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100929 __ LoadFromOffset(kLoadWord, LR, temp,
930 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100931 // LR()
932 __ blx(LR);
933
934 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
935 DCHECK(!codegen_->IsLeafMethod());
936}
937
938void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
939 HandleInvoke(invoke);
940}
941
942void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100943 LocationSummary* locations =
944 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100945 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100946
947 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100948 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100949 HInstruction* input = invoke->InputAt(i);
950 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
951 }
952
953 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100954 case Primitive::kPrimBoolean:
955 case Primitive::kPrimByte:
956 case Primitive::kPrimChar:
957 case Primitive::kPrimShort:
958 case Primitive::kPrimInt:
959 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100960 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100961 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100962 break;
963
964 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100965 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100966 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100967 break;
968
969 case Primitive::kPrimVoid:
970 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100971 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000972}
973
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000974
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100975void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100976 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100977 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
978 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
979 LocationSummary* locations = invoke->GetLocations();
980 Location receiver = locations->InAt(0);
981 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
982 // temp = object->GetClass();
983 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100984 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
985 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100986 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100987 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100988 }
989 // temp = temp->GetMethodAt(method_offset);
990 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100991 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100992 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100993 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100994 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000995 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100996 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100997 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000998}
999
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001000void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001001 LocationSummary* locations =
1002 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001003 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001004 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001005 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001006 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
1007 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1008 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001009 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001010 break;
1011 }
1012
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001013 case Primitive::kPrimFloat:
1014 case Primitive::kPrimDouble: {
1015 locations->SetInAt(0, Location::RequiresFpuRegister());
1016 locations->SetInAt(1, Location::RequiresFpuRegister());
1017 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001018 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001019 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001020
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001021 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001022 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001023 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001024}
1025
1026void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1027 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001028 Location out = locations->Out();
1029 Location first = locations->InAt(0);
1030 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001031 switch (add->GetResultType()) {
1032 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001033 if (second.IsRegister()) {
1034 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001035 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001036 __ AddConstant(out.As<Register>(),
1037 first.As<Register>(),
1038 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001039 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001040 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001041
1042 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001043 __ adds(out.AsRegisterPairLow<Register>(),
1044 first.AsRegisterPairLow<Register>(),
1045 ShifterOperand(second.AsRegisterPairLow<Register>()));
1046 __ adc(out.AsRegisterPairHigh<Register>(),
1047 first.AsRegisterPairHigh<Register>(),
1048 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001049 break;
1050
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001051 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001052 __ vadds(FromDToLowS(out.As<DRegister>()),
1053 FromDToLowS(first.As<DRegister>()),
1054 FromDToLowS(second.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001055 break;
1056
1057 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001058 __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001059 break;
1060
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001061 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001062 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001063 }
1064}
1065
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001066void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001067 LocationSummary* locations =
1068 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001069 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001070 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001071 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001072 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1073 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1074 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001075 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001076 break;
1077 }
1078
1079 case Primitive::kPrimBoolean:
1080 case Primitive::kPrimByte:
1081 case Primitive::kPrimChar:
1082 case Primitive::kPrimShort:
1083 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1084 break;
1085
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001086 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001087 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001088 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001089}
1090
1091void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1092 LocationSummary* locations = sub->GetLocations();
1093 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001094 case Primitive::kPrimInt: {
1095 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001096 __ sub(locations->Out().As<Register>(),
1097 locations->InAt(0).As<Register>(),
1098 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001099 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001100 __ AddConstant(locations->Out().As<Register>(),
1101 locations->InAt(0).As<Register>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001102 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1103 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001104 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001105 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106
1107 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001108 __ subs(locations->Out().AsRegisterPairLow<Register>(),
1109 locations->InAt(0).AsRegisterPairLow<Register>(),
1110 ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
1111 __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
1112 locations->InAt(0).AsRegisterPairHigh<Register>(),
1113 ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001114 break;
1115
1116 case Primitive::kPrimBoolean:
1117 case Primitive::kPrimByte:
1118 case Primitive::kPrimChar:
1119 case Primitive::kPrimShort:
1120 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1121 break;
1122
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001123 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001124 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001125 }
1126}
1127
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001128void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001129 LocationSummary* locations =
1130 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001131 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001132 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1133 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1134 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001135}
1136
1137void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1138 InvokeRuntimeCallingConvention calling_convention;
1139 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1140 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1141
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001142 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001143 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001144 __ blx(LR);
1145
Nicolas Geoffray39468442014-09-02 15:17:15 +01001146 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001147 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001148}
1149
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001150void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001151 LocationSummary* locations =
1152 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001153 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1154 if (location.IsStackSlot()) {
1155 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1156 } else if (location.IsDoubleStackSlot()) {
1157 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001158 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001159 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001160}
1161
1162void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001163 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001164}
1165
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001166void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001167 LocationSummary* locations =
1168 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001169 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001170 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001171}
1172
1173void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1174 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001175 __ eor(locations->Out().As<Register>(),
1176 locations->InAt(0).As<Register>(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001177}
1178
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001179void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001180 LocationSummary* locations =
1181 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001182 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1183 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001184 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001185}
1186
1187void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1188 Label greater, done;
1189 LocationSummary* locations = compare->GetLocations();
1190 switch (compare->InputAt(0)->GetType()) {
1191 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001192 Register output = locations->Out().As<Register>();
1193 Location left = locations->InAt(0);
1194 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001195 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001196 __ cmp(left.AsRegisterPairHigh<Register>(),
1197 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001198 __ b(&less, LT);
1199 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001200 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1201 // the status flags.
1202 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001203 __ cmp(left.AsRegisterPairLow<Register>(),
1204 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001205 __ b(&done, EQ);
1206 __ b(&less, CC);
1207
1208 __ Bind(&greater);
1209 __ LoadImmediate(output, 1);
1210 __ b(&done);
1211
1212 __ Bind(&less);
1213 __ LoadImmediate(output, -1);
1214
1215 __ Bind(&done);
1216 break;
1217 }
1218 default:
1219 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1220 }
1221}
1222
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001223void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001224 LocationSummary* locations =
1225 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001226 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1227 locations->SetInAt(i, Location::Any());
1228 }
1229 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001230}
1231
1232void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001233 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001234}
1235
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001236void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001237 LocationSummary* locations =
1238 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001239 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1240 bool dies_at_entry = !is_object_type;
1241 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1242 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001243 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001244 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001245 locations->AddTemp(Location::RequiresRegister());
1246 locations->AddTemp(Location::RequiresRegister());
1247 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001248}
1249
1250void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1251 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001252 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001253 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001254 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001255
1256 switch (field_type) {
1257 case Primitive::kPrimBoolean:
1258 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001259 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001260 __ StoreToOffset(kStoreByte, value, obj, offset);
1261 break;
1262 }
1263
1264 case Primitive::kPrimShort:
1265 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001266 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001267 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1268 break;
1269 }
1270
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001271 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001272 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001273 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001274 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001275 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001276 Register temp = locations->GetTemp(0).As<Register>();
1277 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001278 codegen_->MarkGCCard(temp, card, obj, value);
1279 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001280 break;
1281 }
1282
1283 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001284 Location value = locations->InAt(1);
1285 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001286 break;
1287 }
1288
1289 case Primitive::kPrimFloat:
1290 case Primitive::kPrimDouble:
1291 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001292 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001293 case Primitive::kPrimVoid:
1294 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001295 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001296 }
1297}
1298
1299void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001300 LocationSummary* locations =
1301 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001302 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001303 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001304}
1305
1306void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1307 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001308 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001309 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1310
1311 switch (instruction->GetType()) {
1312 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001313 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001314 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1315 break;
1316 }
1317
1318 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001319 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001320 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1321 break;
1322 }
1323
1324 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001325 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001326 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1327 break;
1328 }
1329
1330 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001331 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001332 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1333 break;
1334 }
1335
1336 case Primitive::kPrimInt:
1337 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001338 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001339 __ LoadFromOffset(kLoadWord, out, obj, offset);
1340 break;
1341 }
1342
1343 case Primitive::kPrimLong: {
1344 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001345 Location out = locations->Out();
1346 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001347 break;
1348 }
1349
1350 case Primitive::kPrimFloat:
1351 case Primitive::kPrimDouble:
1352 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001353 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001354 case Primitive::kPrimVoid:
1355 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001356 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001357 }
1358}
1359
1360void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001361 LocationSummary* locations =
1362 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001363 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001364 if (instruction->HasUses()) {
1365 locations->SetOut(Location::SameAsFirstInput());
1366 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001367}
1368
1369void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001370 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001371 codegen_->AddSlowPath(slow_path);
1372
1373 LocationSummary* locations = instruction->GetLocations();
1374 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001375
1376 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001377 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001378 __ b(slow_path->GetEntryLabel(), EQ);
1379 } else {
1380 DCHECK(obj.IsConstant()) << obj;
1381 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1382 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001383 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001384}
1385
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001386void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001387 LocationSummary* locations =
1388 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001389 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1390 locations->SetInAt(
1391 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001392 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001393}
1394
1395void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1396 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001397 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001398 Location index = locations->InAt(1);
1399
1400 switch (instruction->GetType()) {
1401 case Primitive::kPrimBoolean: {
1402 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001403 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001404 if (index.IsConstant()) {
1405 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1406 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1407 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001408 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001409 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1410 }
1411 break;
1412 }
1413
1414 case Primitive::kPrimByte: {
1415 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001416 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001417 if (index.IsConstant()) {
1418 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1419 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1420 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001421 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001422 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1423 }
1424 break;
1425 }
1426
1427 case Primitive::kPrimShort: {
1428 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001429 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001430 if (index.IsConstant()) {
1431 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1432 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1433 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001434 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001435 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1436 }
1437 break;
1438 }
1439
1440 case Primitive::kPrimChar: {
1441 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001442 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001443 if (index.IsConstant()) {
1444 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1445 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1446 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001447 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001448 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1449 }
1450 break;
1451 }
1452
1453 case Primitive::kPrimInt:
1454 case Primitive::kPrimNot: {
1455 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1456 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001457 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001458 if (index.IsConstant()) {
1459 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1460 __ LoadFromOffset(kLoadWord, out, obj, offset);
1461 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001462 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001463 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1464 }
1465 break;
1466 }
1467
1468 case Primitive::kPrimLong: {
1469 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001470 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001471 if (index.IsConstant()) {
1472 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001473 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001474 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001475 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1476 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001477 }
1478 break;
1479 }
1480
1481 case Primitive::kPrimFloat:
1482 case Primitive::kPrimDouble:
1483 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001484 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001485 case Primitive::kPrimVoid:
1486 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001487 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001488 }
1489}
1490
1491void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001492 Primitive::Type value_type = instruction->GetComponentType();
1493 bool is_object = value_type == Primitive::kPrimNot;
1494 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1495 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1496 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001497 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001498 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1499 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1500 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001501 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001502 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1503 locations->SetInAt(
1504 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1505 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001506 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001507}
1508
1509void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1510 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001511 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001512 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001513 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001514
1515 switch (value_type) {
1516 case Primitive::kPrimBoolean:
1517 case Primitive::kPrimByte: {
1518 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001519 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001520 if (index.IsConstant()) {
1521 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1522 __ StoreToOffset(kStoreByte, value, obj, offset);
1523 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001524 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001525 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1526 }
1527 break;
1528 }
1529
1530 case Primitive::kPrimShort:
1531 case Primitive::kPrimChar: {
1532 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001533 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001534 if (index.IsConstant()) {
1535 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1536 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1537 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001538 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001539 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1540 }
1541 break;
1542 }
1543
1544 case Primitive::kPrimInt: {
1545 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001546 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001547 if (index.IsConstant()) {
1548 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1549 __ StoreToOffset(kStoreWord, value, obj, offset);
1550 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001551 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001552 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1553 }
1554 break;
1555 }
1556
1557 case Primitive::kPrimNot: {
1558 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001559 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001560 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001561 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001562 DCHECK(!codegen_->IsLeafMethod());
1563 break;
1564 }
1565
1566 case Primitive::kPrimLong: {
1567 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001568 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001569 if (index.IsConstant()) {
1570 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001571 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001572 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001573 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1574 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001575 }
1576 break;
1577 }
1578
1579 case Primitive::kPrimFloat:
1580 case Primitive::kPrimDouble:
1581 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001582 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001583 case Primitive::kPrimVoid:
1584 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001585 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001586 }
1587}
1588
1589void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001590 LocationSummary* locations =
1591 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001592 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001593 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001594}
1595
1596void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1597 LocationSummary* locations = instruction->GetLocations();
1598 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001599 Register obj = locations->InAt(0).As<Register>();
1600 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001601 __ LoadFromOffset(kLoadWord, out, obj, offset);
1602}
1603
1604void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001605 LocationSummary* locations =
1606 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001607 locations->SetInAt(0, Location::RequiresRegister());
1608 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001609 if (instruction->HasUses()) {
1610 locations->SetOut(Location::SameAsFirstInput());
1611 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001612}
1613
1614void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1615 LocationSummary* locations = instruction->GetLocations();
1616 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001617 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001618 codegen_->AddSlowPath(slow_path);
1619
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001620 Register index = locations->InAt(0).As<Register>();
1621 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001622
1623 __ cmp(index, ShifterOperand(length));
1624 __ b(slow_path->GetEntryLabel(), CS);
1625}
1626
1627void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1628 Label is_null;
1629 __ CompareAndBranchIfZero(value, &is_null);
1630 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1631 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1632 __ strb(card, Address(card, temp));
1633 __ Bind(&is_null);
1634}
1635
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001636void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1637 temp->SetLocations(nullptr);
1638}
1639
1640void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1641 // Nothing to do, this is driven by the code generator.
1642}
1643
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001644void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001645 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001646}
1647
1648void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001649 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1650}
1651
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001652void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1653 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1654}
1655
1656void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001657 HBasicBlock* block = instruction->GetBlock();
1658 if (block->GetLoopInformation() != nullptr) {
1659 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1660 // The back edge will generate the suspend check.
1661 return;
1662 }
1663 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1664 // The goto will generate the suspend check.
1665 return;
1666 }
1667 GenerateSuspendCheck(instruction, nullptr);
1668}
1669
1670void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1671 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001672 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001673 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001674 codegen_->AddSlowPath(slow_path);
1675
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001676 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001677 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001678 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001679 __ Bind(slow_path->GetReturnLabel());
1680 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001681 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001682 __ b(slow_path->GetEntryLabel());
1683 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001684}
1685
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001686ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1687 return codegen_->GetAssembler();
1688}
1689
1690void ParallelMoveResolverARM::EmitMove(size_t index) {
1691 MoveOperands* move = moves_.Get(index);
1692 Location source = move->GetSource();
1693 Location destination = move->GetDestination();
1694
1695 if (source.IsRegister()) {
1696 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001697 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001698 } else {
1699 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001700 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001701 SP, destination.GetStackIndex());
1702 }
1703 } else if (source.IsStackSlot()) {
1704 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001705 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001706 SP, source.GetStackIndex());
1707 } else {
1708 DCHECK(destination.IsStackSlot());
1709 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1710 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1711 }
1712 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001713 DCHECK(source.IsConstant());
1714 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1715 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1716 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001717 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001718 } else {
1719 DCHECK(destination.IsStackSlot());
1720 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001721 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001722 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001723 }
1724}
1725
1726void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1727 __ Mov(IP, reg);
1728 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1729 __ StoreToOffset(kStoreWord, IP, SP, mem);
1730}
1731
1732void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1733 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1734 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1735 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1736 SP, mem1 + stack_offset);
1737 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1738 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1739 SP, mem2 + stack_offset);
1740 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1741}
1742
1743void ParallelMoveResolverARM::EmitSwap(size_t index) {
1744 MoveOperands* move = moves_.Get(index);
1745 Location source = move->GetSource();
1746 Location destination = move->GetDestination();
1747
1748 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001749 DCHECK_NE(source.As<Register>(), IP);
1750 DCHECK_NE(destination.As<Register>(), IP);
1751 __ Mov(IP, source.As<Register>());
1752 __ Mov(source.As<Register>(), destination.As<Register>());
1753 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001754 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001755 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001756 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001757 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001758 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1759 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1760 } else {
1761 LOG(FATAL) << "Unimplemented";
1762 }
1763}
1764
1765void ParallelMoveResolverARM::SpillScratch(int reg) {
1766 __ Push(static_cast<Register>(reg));
1767}
1768
1769void ParallelMoveResolverARM::RestoreScratch(int reg) {
1770 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001771}
1772
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001773} // namespace arm
1774} // namespace art