blob: 7a9e9c4ce949766c4648eeb551407704beafe3fb [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)
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100207 : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfDRegisters, kNumberOfRegisterPairs),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100208 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 Geoffray71175b72014-10-09 22:13:55 +0100217Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100218 switch (type) {
219 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100220 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100221 ArmManagedRegister pair =
222 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100223 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
224 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100225 // Block all other register pairs that share a register with `pair`.
226 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
227 ArmManagedRegister current =
228 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
229 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
230 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
231 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
232 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100233 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100234 }
235 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100236 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100237 }
238
239 case Primitive::kPrimByte:
240 case Primitive::kPrimBoolean:
241 case Primitive::kPrimChar:
242 case Primitive::kPrimShort:
243 case Primitive::kPrimInt:
244 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100245 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100246 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100247 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
248 ArmManagedRegister current =
249 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
250 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100251 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100252 }
253 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100254 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100255 }
256
257 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100258 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100259 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfDRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100260 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100261 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100262
263 case Primitive::kPrimVoid:
264 LOG(FATAL) << "Unreachable type " << type;
265 }
266
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100267 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100268}
269
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100270void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100271 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100272 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100273
274 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100275 blocked_core_registers_[SP] = true;
276 blocked_core_registers_[LR] = true;
277 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100278
279 // Reserve R4 for suspend check.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100280 blocked_core_registers_[R4] = true;
281 blocked_register_pairs_[R4_R5] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100282
283 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100284 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100285
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100286 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100287 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100288
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100289 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100290 // We always save and restore R6 and R7 to make sure we can use three
291 // register pairs for long operations.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100292 blocked_core_registers_[R5] = true;
293 blocked_core_registers_[R8] = true;
294 blocked_core_registers_[R10] = true;
295 blocked_core_registers_[R11] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100296
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100297 blocked_fpu_registers_[D8] = true;
298 blocked_fpu_registers_[D9] = true;
299 blocked_fpu_registers_[D10] = true;
300 blocked_fpu_registers_[D11] = true;
301 blocked_fpu_registers_[D12] = true;
302 blocked_fpu_registers_[D13] = true;
303 blocked_fpu_registers_[D14] = true;
304 blocked_fpu_registers_[D15] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100305}
306
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100307InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
308 : HGraphVisitor(graph),
309 assembler_(codegen->GetAssembler()),
310 codegen_(codegen) {}
311
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000312void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700313 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100314 if (!skip_overflow_check) {
315 if (kExplicitStackOverflowCheck) {
316 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
317 AddSlowPath(slow_path);
318
319 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
320 __ cmp(SP, ShifterOperand(IP));
321 __ b(slow_path->GetEntryLabel(), CC);
322 } else {
323 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100324 __ LoadFromOffset(kLoadWord, IP, IP, 0);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100325 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100326 }
327 }
328
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100329 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
330 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000331
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100332 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100333 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100334 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000335}
336
337void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100338 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100339 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000340}
341
342void CodeGeneratorARM::Bind(Label* label) {
343 __ Bind(label);
344}
345
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100346Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
347 switch (load->GetType()) {
348 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100349 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100350 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
351 break;
352
353 case Primitive::kPrimInt:
354 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100355 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100356 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100357
358 case Primitive::kPrimBoolean:
359 case Primitive::kPrimByte:
360 case Primitive::kPrimChar:
361 case Primitive::kPrimShort:
362 case Primitive::kPrimVoid:
363 LOG(FATAL) << "Unexpected type " << load->GetType();
364 }
365
366 LOG(FATAL) << "Unreachable";
367 return Location();
368}
369
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100370Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
371 switch (type) {
372 case Primitive::kPrimBoolean:
373 case Primitive::kPrimByte:
374 case Primitive::kPrimChar:
375 case Primitive::kPrimShort:
376 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100377 case Primitive::kPrimFloat:
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100378 case Primitive::kPrimNot: {
379 uint32_t index = gp_index_++;
380 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100381 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100382 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100383 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100384 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100385 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100386
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100387 case Primitive::kPrimLong:
388 case Primitive::kPrimDouble: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100389 uint32_t index = gp_index_;
390 gp_index_ += 2;
391 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100392 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
393 calling_convention.GetRegisterPairAt(index));
394 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100395 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
396 return Location::QuickParameter(index);
397 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100399 }
400 }
401
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100402 case Primitive::kPrimVoid:
403 LOG(FATAL) << "Unexpected parameter type " << type;
404 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100405 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100406 return Location();
407}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100408
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100409void CodeGeneratorARM::Move32(Location destination, Location source) {
410 if (source.Equals(destination)) {
411 return;
412 }
413 if (destination.IsRegister()) {
414 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100415 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100416 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100417 __ vmovrs(destination.As<Register>(), FromDToLowS(source.As<DRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100418 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100419 __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100420 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100421 } else if (destination.IsFpuRegister()) {
422 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100423 __ vmovsr(FromDToLowS(destination.As<DRegister>()), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100424 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100425 __ vmovs(FromDToLowS(destination.As<DRegister>()), FromDToLowS(source.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100426 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100427 __ vldrs(FromDToLowS(destination.As<DRegister>()), Address(SP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100428 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100429 } else {
430 DCHECK(destination.IsStackSlot());
431 if (source.IsRegister()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100432 __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100433 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100434 __ vstrs(FromDToLowS(source.As<DRegister>()), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100435 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100436 DCHECK(source.IsStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100437 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
438 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100439 }
440 }
441}
442
443void CodeGeneratorARM::Move64(Location destination, Location source) {
444 if (source.Equals(destination)) {
445 return;
446 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100447 if (destination.IsRegisterPair()) {
448 if (source.IsRegisterPair()) {
449 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
450 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100451 } else if (source.IsFpuRegister()) {
452 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100453 } else if (source.IsQuickParameter()) {
454 uint32_t argument_index = source.GetQuickParameterIndex();
455 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100456 __ Mov(destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100457 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100458 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(),
459 SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100460 } else {
461 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100462 if (destination.AsRegisterPairLow<Register>() == R1) {
463 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100464 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
465 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100466 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100467 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100468 SP, source.GetStackIndex());
469 }
470 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100471 } else if (destination.IsFpuRegister()) {
472 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100473 __ vldrd(destination.As<DRegister>(), Address(SP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100474 } else {
475 LOG(FATAL) << "Unimplemented";
476 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100477 } else if (destination.IsQuickParameter()) {
478 InvokeDexCallingConvention calling_convention;
479 uint32_t argument_index = destination.GetQuickParameterIndex();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100480 if (source.IsRegisterPair()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100481 __ Mov(calling_convention.GetRegisterAt(argument_index),
482 source.AsRegisterPairLow<Register>());
483 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(),
484 SP, calling_convention.GetStackOffsetOf(argument_index + 1));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100485 } else if (source.IsFpuRegister()) {
486 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100487 } else {
488 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100489 __ LoadFromOffset(kLoadWord, calling_convention.GetRegisterAt(argument_index), SP, source.GetStackIndex());
490 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize));
491 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(argument_index + 1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100492 }
493 } else {
494 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100495 if (source.IsRegisterPair()) {
496 if (source.AsRegisterPairLow<Register>() == R1) {
497 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100498 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
499 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100500 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100501 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100502 SP, destination.GetStackIndex());
503 }
504 } else if (source.IsQuickParameter()) {
505 InvokeDexCallingConvention calling_convention;
506 uint32_t argument_index = source.GetQuickParameterIndex();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100507 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(argument_index),
508 SP, destination.GetStackIndex());
509 __ LoadFromOffset(kLoadWord, R0,
510 SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize());
511 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100512 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100513 __ vstrd(source.As<DRegister>(), Address(SP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100514 } else {
515 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100516 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
517 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
518 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
519 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100520 }
521 }
522}
523
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100524void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100525 LocationSummary* locations = instruction->GetLocations();
526 if (locations != nullptr && locations->Out().Equals(location)) {
527 return;
528 }
529
Roland Levillain476df552014-10-09 17:51:36 +0100530 if (instruction->IsIntConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100531 int32_t value = instruction->AsIntConstant()->GetValue();
532 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100533 __ LoadImmediate(location.As<Register>(), value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100534 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100535 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100536 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100537 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100538 }
Roland Levillain476df552014-10-09 17:51:36 +0100539 } else if (instruction->IsLongConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100540 int64_t value = instruction->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100541 if (location.IsRegisterPair()) {
542 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
543 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100544 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100545 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100546 __ LoadImmediate(IP, Low32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100547 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100548 __ LoadImmediate(IP, High32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100549 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100550 }
Roland Levillain476df552014-10-09 17:51:36 +0100551 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100552 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
553 switch (instruction->GetType()) {
554 case Primitive::kPrimBoolean:
555 case Primitive::kPrimByte:
556 case Primitive::kPrimChar:
557 case Primitive::kPrimShort:
558 case Primitive::kPrimInt:
559 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100560 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100561 Move32(location, Location::StackSlot(stack_slot));
562 break;
563
564 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100565 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100566 Move64(location, Location::DoubleStackSlot(stack_slot));
567 break;
568
569 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100570 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100571 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000572 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100573 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100574 switch (instruction->GetType()) {
575 case Primitive::kPrimBoolean:
576 case Primitive::kPrimByte:
577 case Primitive::kPrimChar:
578 case Primitive::kPrimShort:
579 case Primitive::kPrimNot:
580 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100581 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100582 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100583 break;
584
585 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100586 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100587 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100588 break;
589
590 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100591 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100592 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000593 }
594}
595
596void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000597 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000598}
599
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000600void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000601 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100602 DCHECK(!successor->IsExitBlock());
603
604 HBasicBlock* block = got->GetBlock();
605 HInstruction* previous = got->GetPrevious();
606
607 HLoopInformation* info = block->GetLoopInformation();
608 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
609 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
610 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
611 return;
612 }
613
614 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
615 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
616 }
617 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000618 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000619 }
620}
621
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000622void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000623 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000624}
625
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000626void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000627 if (kIsDebugBuild) {
628 __ Comment("Unreachable");
629 __ bkpt(0);
630 }
631}
632
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000633void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100634 LocationSummary* locations =
635 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100636 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100637 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100638 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100639 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000640}
641
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000642void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700643 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100644 if (cond->IsIntConstant()) {
645 // Constant condition, statically compared against 1.
646 int32_t cond_value = cond->AsIntConstant()->GetValue();
647 if (cond_value == 1) {
648 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
649 if_instr->IfTrueSuccessor())) {
650 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100651 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100652 return;
653 } else {
654 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100655 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100656 } else {
657 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
658 // Condition has been materialized, compare the output to 0
659 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
660 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
661 ShifterOperand(0));
662 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
663 } else {
664 // Condition has not been materialized, use its inputs as the
665 // comparison and its condition as the branch condition.
666 LocationSummary* locations = cond->GetLocations();
667 if (locations->InAt(1).IsRegister()) {
668 __ cmp(locations->InAt(0).As<Register>(),
669 ShifterOperand(locations->InAt(1).As<Register>()));
670 } else {
671 DCHECK(locations->InAt(1).IsConstant());
672 int32_t value =
673 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
674 ShifterOperand operand;
675 if (ShifterOperand::CanHoldArm(value, &operand)) {
676 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
677 } else {
678 Register temp = IP;
679 __ LoadImmediate(temp, value);
680 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
681 }
682 }
683 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
684 ARMCondition(cond->AsCondition()->GetCondition()));
685 }
Dave Allison20dfc792014-06-16 20:44:29 -0700686 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100687 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
688 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700689 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000690 }
691}
692
Dave Allison20dfc792014-06-16 20:44:29 -0700693
694void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100695 LocationSummary* locations =
696 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100697 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
698 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100699 if (comp->NeedsMaterialization()) {
700 locations->SetOut(Location::RequiresRegister());
701 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000702}
703
Dave Allison20dfc792014-06-16 20:44:29 -0700704void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100705 if (!comp->NeedsMaterialization()) return;
706
707 LocationSummary* locations = comp->GetLocations();
708 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100709 __ cmp(locations->InAt(0).As<Register>(),
710 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100711 } else {
712 DCHECK(locations->InAt(1).IsConstant());
713 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
714 ShifterOperand operand;
715 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100716 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100717 } else {
718 Register temp = IP;
719 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100720 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100721 }
Dave Allison20dfc792014-06-16 20:44:29 -0700722 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100723 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100724 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100725 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100726 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100727 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700728}
729
730void LocationsBuilderARM::VisitEqual(HEqual* comp) {
731 VisitCondition(comp);
732}
733
734void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
735 VisitCondition(comp);
736}
737
738void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
739 VisitCondition(comp);
740}
741
742void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
743 VisitCondition(comp);
744}
745
746void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
747 VisitCondition(comp);
748}
749
750void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
751 VisitCondition(comp);
752}
753
754void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
755 VisitCondition(comp);
756}
757
758void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
759 VisitCondition(comp);
760}
761
762void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
763 VisitCondition(comp);
764}
765
766void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
767 VisitCondition(comp);
768}
769
770void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
771 VisitCondition(comp);
772}
773
774void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
775 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000776}
777
778void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000779 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000780}
781
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000782void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
783 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000784}
785
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000786void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100787 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000788}
789
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000790void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100791 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000792}
793
794void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100795 LocationSummary* locations =
796 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100797 switch (store->InputAt(1)->GetType()) {
798 case Primitive::kPrimBoolean:
799 case Primitive::kPrimByte:
800 case Primitive::kPrimChar:
801 case Primitive::kPrimShort:
802 case Primitive::kPrimInt:
803 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100804 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100805 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
806 break;
807
808 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100809 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100810 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
811 break;
812
813 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100814 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100815 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000816}
817
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000818void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000819}
820
821void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100822 LocationSummary* locations =
823 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100824 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000825}
826
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000827void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100828 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000829}
830
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100831void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100832 LocationSummary* locations =
833 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100834 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100835}
836
837void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
838 // Will be generated at use site.
839}
840
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000841void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000842 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000843}
844
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000845void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
846 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000847}
848
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000849void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100850 LocationSummary* locations =
851 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100852 switch (ret->InputAt(0)->GetType()) {
853 case Primitive::kPrimBoolean:
854 case Primitive::kPrimByte:
855 case Primitive::kPrimChar:
856 case Primitive::kPrimShort:
857 case Primitive::kPrimInt:
858 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100859 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100860 locations->SetInAt(0, Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100861 break;
862
863 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100864 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100865 locations->SetInAt(0, Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100866 break;
867
868 default:
869 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
870 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000871}
872
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000873void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 if (kIsDebugBuild) {
875 switch (ret->InputAt(0)->GetType()) {
876 case Primitive::kPrimBoolean:
877 case Primitive::kPrimByte:
878 case Primitive::kPrimChar:
879 case Primitive::kPrimShort:
880 case Primitive::kPrimInt:
881 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100882 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100883 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100884 break;
885
886 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100887 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100888 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0);
889 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 break;
891
892 default:
893 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
894 }
895 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000896 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000897}
898
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000899void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100900 HandleInvoke(invoke);
901}
902
903void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100904 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100905}
906
907void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100908 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100909 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
910 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
911 invoke->GetIndexInDexCache() * kArmWordSize;
912
913 // TODO: Implement all kinds of calls:
914 // 1) boot -> boot
915 // 2) app -> boot
916 // 3) app -> app
917 //
918 // Currently we implement the app -> app logic, which looks up in the resolve cache.
919
920 // temp = method;
921 LoadCurrentMethod(temp);
922 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100923 __ LoadFromOffset(kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100924 // temp = temp[index_in_cache]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100925 __ LoadFromOffset(kLoadWord, temp, temp, index_in_cache);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100926 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100927 __ LoadFromOffset(kLoadWord, LR, temp,
928 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100929 // LR()
930 __ blx(LR);
931
932 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
933 DCHECK(!codegen_->IsLeafMethod());
934}
935
936void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
937 HandleInvoke(invoke);
938}
939
940void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100941 LocationSummary* locations =
942 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100943 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100944
945 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100946 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100947 HInstruction* input = invoke->InputAt(i);
948 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
949 }
950
951 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100952 case Primitive::kPrimBoolean:
953 case Primitive::kPrimByte:
954 case Primitive::kPrimChar:
955 case Primitive::kPrimShort:
956 case Primitive::kPrimInt:
957 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100958 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100959 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100960 break;
961
962 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100963 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100964 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100965 break;
966
967 case Primitive::kPrimVoid:
968 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100969 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000970}
971
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000972
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100973void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100974 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100975 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
976 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
977 LocationSummary* locations = invoke->GetLocations();
978 Location receiver = locations->InAt(0);
979 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
980 // temp = object->GetClass();
981 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100982 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
983 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100984 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100985 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100986 }
987 // temp = temp->GetMethodAt(method_offset);
988 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100989 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100990 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100991 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100992 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000993 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100994 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100995 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000996}
997
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000998void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100999 LocationSummary* locations =
1000 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001001 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001002 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001003 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001004 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
1005 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1006 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001007 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001008 break;
1009 }
1010
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001011 case Primitive::kPrimFloat:
1012 case Primitive::kPrimDouble: {
1013 locations->SetInAt(0, Location::RequiresFpuRegister());
1014 locations->SetInAt(1, Location::RequiresFpuRegister());
1015 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001016 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001017 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001018
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001019 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001020 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001021 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001022}
1023
1024void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1025 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001026 Location out = locations->Out();
1027 Location first = locations->InAt(0);
1028 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001029 switch (add->GetResultType()) {
1030 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001031 if (second.IsRegister()) {
1032 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001033 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001034 __ AddConstant(out.As<Register>(),
1035 first.As<Register>(),
1036 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001037 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001038 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001039
1040 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001041 __ adds(out.AsRegisterPairLow<Register>(),
1042 first.AsRegisterPairLow<Register>(),
1043 ShifterOperand(second.AsRegisterPairLow<Register>()));
1044 __ adc(out.AsRegisterPairHigh<Register>(),
1045 first.AsRegisterPairHigh<Register>(),
1046 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001047 break;
1048
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001049 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001050 __ vadds(FromDToLowS(out.As<DRegister>()),
1051 FromDToLowS(first.As<DRegister>()),
1052 FromDToLowS(second.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001053 break;
1054
1055 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001056 __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001057 break;
1058
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001059 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001060 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001061 }
1062}
1063
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001064void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001065 LocationSummary* locations =
1066 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001067 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001068 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001069 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001070 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1071 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1072 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001073 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001074 break;
1075 }
1076
1077 case Primitive::kPrimBoolean:
1078 case Primitive::kPrimByte:
1079 case Primitive::kPrimChar:
1080 case Primitive::kPrimShort:
1081 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1082 break;
1083
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001084 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001085 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001086 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001087}
1088
1089void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1090 LocationSummary* locations = sub->GetLocations();
1091 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001092 case Primitive::kPrimInt: {
1093 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001094 __ sub(locations->Out().As<Register>(),
1095 locations->InAt(0).As<Register>(),
1096 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001097 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001098 __ AddConstant(locations->Out().As<Register>(),
1099 locations->InAt(0).As<Register>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001100 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1101 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001102 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001103 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001104
1105 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001106 __ subs(locations->Out().AsRegisterPairLow<Register>(),
1107 locations->InAt(0).AsRegisterPairLow<Register>(),
1108 ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
1109 __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
1110 locations->InAt(0).AsRegisterPairHigh<Register>(),
1111 ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001112 break;
1113
1114 case Primitive::kPrimBoolean:
1115 case Primitive::kPrimByte:
1116 case Primitive::kPrimChar:
1117 case Primitive::kPrimShort:
1118 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1119 break;
1120
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001121 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001122 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001123 }
1124}
1125
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001126void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001127 LocationSummary* locations =
1128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001129 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001130 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1131 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1132 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001133}
1134
1135void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1136 InvokeRuntimeCallingConvention calling_convention;
1137 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1138 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1139
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001140 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001141 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001142 __ blx(LR);
1143
Nicolas Geoffray39468442014-09-02 15:17:15 +01001144 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001145 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001146}
1147
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001148void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001149 LocationSummary* locations =
1150 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001151 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1152 if (location.IsStackSlot()) {
1153 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1154 } else if (location.IsDoubleStackSlot()) {
1155 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001156 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001157 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001158}
1159
1160void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001161 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001162}
1163
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001164void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001165 LocationSummary* locations =
1166 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001167 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001168 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001169}
1170
1171void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1172 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001173 __ eor(locations->Out().As<Register>(),
1174 locations->InAt(0).As<Register>(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001175}
1176
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001177void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001178 LocationSummary* locations =
1179 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001180 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1181 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001182 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001183}
1184
1185void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1186 Label greater, done;
1187 LocationSummary* locations = compare->GetLocations();
1188 switch (compare->InputAt(0)->GetType()) {
1189 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001190 Register output = locations->Out().As<Register>();
1191 Location left = locations->InAt(0);
1192 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001193 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001194 __ cmp(left.AsRegisterPairHigh<Register>(),
1195 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001196 __ b(&less, LT);
1197 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001198 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1199 // the status flags.
1200 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001201 __ cmp(left.AsRegisterPairLow<Register>(),
1202 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001203 __ b(&done, EQ);
1204 __ b(&less, CC);
1205
1206 __ Bind(&greater);
1207 __ LoadImmediate(output, 1);
1208 __ b(&done);
1209
1210 __ Bind(&less);
1211 __ LoadImmediate(output, -1);
1212
1213 __ Bind(&done);
1214 break;
1215 }
1216 default:
1217 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1218 }
1219}
1220
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001221void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001222 LocationSummary* locations =
1223 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001224 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1225 locations->SetInAt(i, Location::Any());
1226 }
1227 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001228}
1229
1230void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001231 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001232}
1233
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001234void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001235 LocationSummary* locations =
1236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001237 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1238 bool dies_at_entry = !is_object_type;
1239 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1240 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001241 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001242 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001243 locations->AddTemp(Location::RequiresRegister());
1244 locations->AddTemp(Location::RequiresRegister());
1245 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001246}
1247
1248void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1249 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001250 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001251 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001252 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001253
1254 switch (field_type) {
1255 case Primitive::kPrimBoolean:
1256 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001257 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001258 __ StoreToOffset(kStoreByte, value, obj, offset);
1259 break;
1260 }
1261
1262 case Primitive::kPrimShort:
1263 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001264 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001265 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1266 break;
1267 }
1268
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001269 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001270 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001271 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001272 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001273 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001274 Register temp = locations->GetTemp(0).As<Register>();
1275 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001276 codegen_->MarkGCCard(temp, card, obj, value);
1277 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001278 break;
1279 }
1280
1281 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001282 Location value = locations->InAt(1);
1283 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001284 break;
1285 }
1286
1287 case Primitive::kPrimFloat:
1288 case Primitive::kPrimDouble:
1289 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001290 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001291 case Primitive::kPrimVoid:
1292 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001293 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001294 }
1295}
1296
1297void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001298 LocationSummary* locations =
1299 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001300 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001301 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001302}
1303
1304void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1305 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001306 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001307 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1308
1309 switch (instruction->GetType()) {
1310 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001311 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001312 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1313 break;
1314 }
1315
1316 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001317 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001318 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1319 break;
1320 }
1321
1322 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001323 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001324 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1325 break;
1326 }
1327
1328 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001329 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001330 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1331 break;
1332 }
1333
1334 case Primitive::kPrimInt:
1335 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001336 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001337 __ LoadFromOffset(kLoadWord, out, obj, offset);
1338 break;
1339 }
1340
1341 case Primitive::kPrimLong: {
1342 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001343 Location out = locations->Out();
1344 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001345 break;
1346 }
1347
1348 case Primitive::kPrimFloat:
1349 case Primitive::kPrimDouble:
1350 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001351 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001352 case Primitive::kPrimVoid:
1353 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001354 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001355 }
1356}
1357
1358void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001359 LocationSummary* locations =
1360 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001361 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001362 if (instruction->HasUses()) {
1363 locations->SetOut(Location::SameAsFirstInput());
1364 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001365}
1366
1367void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001368 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001369 codegen_->AddSlowPath(slow_path);
1370
1371 LocationSummary* locations = instruction->GetLocations();
1372 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001373
1374 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001375 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001376 __ b(slow_path->GetEntryLabel(), EQ);
1377 } else {
1378 DCHECK(obj.IsConstant()) << obj;
1379 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1380 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001381 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001382}
1383
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001384void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001385 LocationSummary* locations =
1386 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001387 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1388 locations->SetInAt(
1389 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001390 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001391}
1392
1393void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1394 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001395 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001396 Location index = locations->InAt(1);
1397
1398 switch (instruction->GetType()) {
1399 case Primitive::kPrimBoolean: {
1400 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001401 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001402 if (index.IsConstant()) {
1403 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1404 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1405 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001406 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001407 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1408 }
1409 break;
1410 }
1411
1412 case Primitive::kPrimByte: {
1413 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001414 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001415 if (index.IsConstant()) {
1416 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1417 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1418 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001419 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001420 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1421 }
1422 break;
1423 }
1424
1425 case Primitive::kPrimShort: {
1426 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001427 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001428 if (index.IsConstant()) {
1429 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1430 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1431 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001432 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001433 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1434 }
1435 break;
1436 }
1437
1438 case Primitive::kPrimChar: {
1439 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001440 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001441 if (index.IsConstant()) {
1442 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1443 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1444 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001445 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001446 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1447 }
1448 break;
1449 }
1450
1451 case Primitive::kPrimInt:
1452 case Primitive::kPrimNot: {
1453 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1454 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001455 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001456 if (index.IsConstant()) {
1457 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1458 __ LoadFromOffset(kLoadWord, out, obj, offset);
1459 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001460 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001461 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1462 }
1463 break;
1464 }
1465
1466 case Primitive::kPrimLong: {
1467 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001468 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001469 if (index.IsConstant()) {
1470 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001471 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001472 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001473 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1474 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001475 }
1476 break;
1477 }
1478
1479 case Primitive::kPrimFloat:
1480 case Primitive::kPrimDouble:
1481 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001482 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001483 case Primitive::kPrimVoid:
1484 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001485 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001486 }
1487}
1488
1489void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001490 Primitive::Type value_type = instruction->GetComponentType();
1491 bool is_object = value_type == Primitive::kPrimNot;
1492 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1493 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1494 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001495 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001496 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1497 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1498 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001499 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001500 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1501 locations->SetInAt(
1502 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1503 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001504 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001505}
1506
1507void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1508 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001509 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001510 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001511 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001512
1513 switch (value_type) {
1514 case Primitive::kPrimBoolean:
1515 case Primitive::kPrimByte: {
1516 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001517 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001518 if (index.IsConstant()) {
1519 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1520 __ StoreToOffset(kStoreByte, value, obj, offset);
1521 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001522 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001523 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1524 }
1525 break;
1526 }
1527
1528 case Primitive::kPrimShort:
1529 case Primitive::kPrimChar: {
1530 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001531 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001532 if (index.IsConstant()) {
1533 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1534 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1535 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001536 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001537 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1538 }
1539 break;
1540 }
1541
1542 case Primitive::kPrimInt: {
1543 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001544 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001545 if (index.IsConstant()) {
1546 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1547 __ StoreToOffset(kStoreWord, value, obj, offset);
1548 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001549 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001550 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1551 }
1552 break;
1553 }
1554
1555 case Primitive::kPrimNot: {
1556 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001557 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001558 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001559 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001560 DCHECK(!codegen_->IsLeafMethod());
1561 break;
1562 }
1563
1564 case Primitive::kPrimLong: {
1565 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001566 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001567 if (index.IsConstant()) {
1568 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001569 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001570 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001571 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1572 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001573 }
1574 break;
1575 }
1576
1577 case Primitive::kPrimFloat:
1578 case Primitive::kPrimDouble:
1579 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001580 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001581 case Primitive::kPrimVoid:
1582 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001583 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001584 }
1585}
1586
1587void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001588 LocationSummary* locations =
1589 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001590 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001591 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001592}
1593
1594void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1595 LocationSummary* locations = instruction->GetLocations();
1596 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001597 Register obj = locations->InAt(0).As<Register>();
1598 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001599 __ LoadFromOffset(kLoadWord, out, obj, offset);
1600}
1601
1602void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001603 LocationSummary* locations =
1604 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001605 locations->SetInAt(0, Location::RequiresRegister());
1606 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001607 if (instruction->HasUses()) {
1608 locations->SetOut(Location::SameAsFirstInput());
1609 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001610}
1611
1612void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1613 LocationSummary* locations = instruction->GetLocations();
1614 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001615 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001616 codegen_->AddSlowPath(slow_path);
1617
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001618 Register index = locations->InAt(0).As<Register>();
1619 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001620
1621 __ cmp(index, ShifterOperand(length));
1622 __ b(slow_path->GetEntryLabel(), CS);
1623}
1624
1625void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1626 Label is_null;
1627 __ CompareAndBranchIfZero(value, &is_null);
1628 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1629 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1630 __ strb(card, Address(card, temp));
1631 __ Bind(&is_null);
1632}
1633
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001634void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1635 temp->SetLocations(nullptr);
1636}
1637
1638void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1639 // Nothing to do, this is driven by the code generator.
1640}
1641
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001642void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001643 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001644}
1645
1646void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001647 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1648}
1649
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001650void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1651 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1652}
1653
1654void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001655 HBasicBlock* block = instruction->GetBlock();
1656 if (block->GetLoopInformation() != nullptr) {
1657 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1658 // The back edge will generate the suspend check.
1659 return;
1660 }
1661 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1662 // The goto will generate the suspend check.
1663 return;
1664 }
1665 GenerateSuspendCheck(instruction, nullptr);
1666}
1667
1668void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1669 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001670 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001671 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001672 codegen_->AddSlowPath(slow_path);
1673
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001674 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001675 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001676 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001677 __ Bind(slow_path->GetReturnLabel());
1678 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001679 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001680 __ b(slow_path->GetEntryLabel());
1681 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001682}
1683
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001684ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1685 return codegen_->GetAssembler();
1686}
1687
1688void ParallelMoveResolverARM::EmitMove(size_t index) {
1689 MoveOperands* move = moves_.Get(index);
1690 Location source = move->GetSource();
1691 Location destination = move->GetDestination();
1692
1693 if (source.IsRegister()) {
1694 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001695 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001696 } else {
1697 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001698 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001699 SP, destination.GetStackIndex());
1700 }
1701 } else if (source.IsStackSlot()) {
1702 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001703 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001704 SP, source.GetStackIndex());
1705 } else {
1706 DCHECK(destination.IsStackSlot());
1707 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1708 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1709 }
1710 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001711 DCHECK(source.IsConstant());
Roland Levillain476df552014-10-09 17:51:36 +01001712 DCHECK(source.GetConstant()->IsIntConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001713 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1714 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001715 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001716 } else {
1717 DCHECK(destination.IsStackSlot());
1718 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001719 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001720 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001721 }
1722}
1723
1724void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1725 __ Mov(IP, reg);
1726 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1727 __ StoreToOffset(kStoreWord, IP, SP, mem);
1728}
1729
1730void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1731 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1732 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1733 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1734 SP, mem1 + stack_offset);
1735 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1736 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1737 SP, mem2 + stack_offset);
1738 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1739}
1740
1741void ParallelMoveResolverARM::EmitSwap(size_t index) {
1742 MoveOperands* move = moves_.Get(index);
1743 Location source = move->GetSource();
1744 Location destination = move->GetDestination();
1745
1746 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001747 DCHECK_NE(source.As<Register>(), IP);
1748 DCHECK_NE(destination.As<Register>(), IP);
1749 __ Mov(IP, source.As<Register>());
1750 __ Mov(source.As<Register>(), destination.As<Register>());
1751 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001752 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001753 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001754 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001755 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001756 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1757 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1758 } else {
1759 LOG(FATAL) << "Unimplemented";
1760 }
1761}
1762
1763void ParallelMoveResolverARM::SpillScratch(int reg) {
1764 __ Push(static_cast<Register>(reg));
1765}
1766
1767void ParallelMoveResolverARM::RestoreScratch(int reg) {
1768 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001769}
1770
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001771} // namespace arm
1772} // namespace art