blob: 2be5c90ed673f44160aed4ed2fb6f844f99f100a [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
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100530 if (instruction->AsIntConstant() != nullptr) {
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 }
539 } else if (instruction->AsLongConstant() != nullptr) {
540 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 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100551 } else if (instruction->AsLoadLocal() != nullptr) {
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);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100644 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Dave Allison20dfc792014-06-16 20:44:29 -0700645 // Condition has been materialized, compare the output to 0
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100646 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100647 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
Dave Allison20dfc792014-06-16 20:44:29 -0700648 ShifterOperand(0));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100649 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
Dave Allison20dfc792014-06-16 20:44:29 -0700650 } else {
651 // Condition has not been materialized, use its inputs as the comparison and its
652 // condition as the branch condition.
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100653 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100654 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100655 __ cmp(locations->InAt(0).As<Register>(),
656 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100657 } else {
658 DCHECK(locations->InAt(1).IsConstant());
659 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
660 ShifterOperand operand;
661 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100662 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100663 } else {
664 Register temp = IP;
665 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100666 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100667 }
668 }
Dave Allison20dfc792014-06-16 20:44:29 -0700669 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100670 ARMCondition(cond->AsCondition()->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700671 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100672
Dave Allison20dfc792014-06-16 20:44:29 -0700673 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
674 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000675 }
676}
677
Dave Allison20dfc792014-06-16 20:44:29 -0700678
679void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100680 LocationSummary* locations =
681 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100682 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
683 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100684 if (comp->NeedsMaterialization()) {
685 locations->SetOut(Location::RequiresRegister());
686 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000687}
688
Dave Allison20dfc792014-06-16 20:44:29 -0700689void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100690 if (!comp->NeedsMaterialization()) return;
691
692 LocationSummary* locations = comp->GetLocations();
693 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100694 __ cmp(locations->InAt(0).As<Register>(),
695 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100696 } else {
697 DCHECK(locations->InAt(1).IsConstant());
698 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
699 ShifterOperand operand;
700 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100701 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100702 } else {
703 Register temp = IP;
704 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100705 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100706 }
Dave Allison20dfc792014-06-16 20:44:29 -0700707 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100708 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100709 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100710 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100711 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100712 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700713}
714
715void LocationsBuilderARM::VisitEqual(HEqual* comp) {
716 VisitCondition(comp);
717}
718
719void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
720 VisitCondition(comp);
721}
722
723void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
724 VisitCondition(comp);
725}
726
727void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
728 VisitCondition(comp);
729}
730
731void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
732 VisitCondition(comp);
733}
734
735void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
736 VisitCondition(comp);
737}
738
739void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
740 VisitCondition(comp);
741}
742
743void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
744 VisitCondition(comp);
745}
746
747void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
748 VisitCondition(comp);
749}
750
751void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
752 VisitCondition(comp);
753}
754
755void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
756 VisitCondition(comp);
757}
758
759void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
760 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000761}
762
763void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000764 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000765}
766
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000767void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
768 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000769}
770
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000771void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100772 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000773}
774
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000775void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100776 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000777}
778
779void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100780 LocationSummary* locations =
781 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100782 switch (store->InputAt(1)->GetType()) {
783 case Primitive::kPrimBoolean:
784 case Primitive::kPrimByte:
785 case Primitive::kPrimChar:
786 case Primitive::kPrimShort:
787 case Primitive::kPrimInt:
788 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100789 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100790 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
791 break;
792
793 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100794 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100795 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
796 break;
797
798 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100799 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100800 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000801}
802
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000803void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000804}
805
806void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100807 LocationSummary* locations =
808 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100809 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000810}
811
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000812void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000813}
814
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100815void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100816 LocationSummary* locations =
817 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100818 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100819}
820
821void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
822 // Will be generated at use site.
823}
824
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000825void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000826 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000827}
828
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000829void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
830 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000831}
832
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000833void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100834 LocationSummary* locations =
835 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100836 switch (ret->InputAt(0)->GetType()) {
837 case Primitive::kPrimBoolean:
838 case Primitive::kPrimByte:
839 case Primitive::kPrimChar:
840 case Primitive::kPrimShort:
841 case Primitive::kPrimInt:
842 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100843 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100844 locations->SetInAt(0, Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100845 break;
846
847 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100848 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100849 locations->SetInAt(0, Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100850 break;
851
852 default:
853 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
854 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000855}
856
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000857void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100858 if (kIsDebugBuild) {
859 switch (ret->InputAt(0)->GetType()) {
860 case Primitive::kPrimBoolean:
861 case Primitive::kPrimByte:
862 case Primitive::kPrimChar:
863 case Primitive::kPrimShort:
864 case Primitive::kPrimInt:
865 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100867 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100868 break;
869
870 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100871 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100872 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0);
873 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 break;
875
876 default:
877 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
878 }
879 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000880 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000881}
882
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000883void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100884 HandleInvoke(invoke);
885}
886
887void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100888 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100889}
890
891void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100892 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100893 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
894 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
895 invoke->GetIndexInDexCache() * kArmWordSize;
896
897 // TODO: Implement all kinds of calls:
898 // 1) boot -> boot
899 // 2) app -> boot
900 // 3) app -> app
901 //
902 // Currently we implement the app -> app logic, which looks up in the resolve cache.
903
904 // temp = method;
905 LoadCurrentMethod(temp);
906 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100907 __ LoadFromOffset(kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100908 // temp = temp[index_in_cache]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100909 __ LoadFromOffset(kLoadWord, temp, temp, index_in_cache);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100910 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100911 __ LoadFromOffset(kLoadWord, LR, temp,
912 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100913 // LR()
914 __ blx(LR);
915
916 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
917 DCHECK(!codegen_->IsLeafMethod());
918}
919
920void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
921 HandleInvoke(invoke);
922}
923
924void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100925 LocationSummary* locations =
926 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100927 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100928
929 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100930 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100931 HInstruction* input = invoke->InputAt(i);
932 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
933 }
934
935 switch (invoke->GetType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100936 case Primitive::kPrimBoolean:
937 case Primitive::kPrimByte:
938 case Primitive::kPrimChar:
939 case Primitive::kPrimShort:
940 case Primitive::kPrimInt:
941 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100942 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100943 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100944 break;
945
946 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100947 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100948 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100949 break;
950
951 case Primitive::kPrimVoid:
952 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100953 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000954}
955
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000956
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100957void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100958 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100959 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
960 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
961 LocationSummary* locations = invoke->GetLocations();
962 Location receiver = locations->InAt(0);
963 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
964 // temp = object->GetClass();
965 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100966 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
967 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100968 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100969 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100970 }
971 // temp = temp->GetMethodAt(method_offset);
972 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100973 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100974 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100975 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100976 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000977 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100978 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100979 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000980}
981
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000982void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100983 LocationSummary* locations =
984 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000985 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100986 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100987 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +0100988 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
989 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
990 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100991 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100992 break;
993 }
994
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100995 case Primitive::kPrimFloat:
996 case Primitive::kPrimDouble: {
997 locations->SetInAt(0, Location::RequiresFpuRegister());
998 locations->SetInAt(1, Location::RequiresFpuRegister());
999 locations->SetOut(Location::RequiresFpuRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001000 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001001 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001002
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001003 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001004 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001005 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001006}
1007
1008void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1009 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001010 Location out = locations->Out();
1011 Location first = locations->InAt(0);
1012 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001013 switch (add->GetResultType()) {
1014 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001015 if (second.IsRegister()) {
1016 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001017 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001018 __ AddConstant(out.As<Register>(),
1019 first.As<Register>(),
1020 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001021 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001022 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001023
1024 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001025 __ adds(out.AsRegisterPairLow<Register>(),
1026 first.AsRegisterPairLow<Register>(),
1027 ShifterOperand(second.AsRegisterPairLow<Register>()));
1028 __ adc(out.AsRegisterPairHigh<Register>(),
1029 first.AsRegisterPairHigh<Register>(),
1030 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001031 break;
1032
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001033 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001034 __ vadds(FromDToLowS(out.As<DRegister>()),
1035 FromDToLowS(first.As<DRegister>()),
1036 FromDToLowS(second.As<DRegister>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001037 break;
1038
1039 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001040 __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001041 break;
1042
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001043 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001044 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001045 }
1046}
1047
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001048void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001049 LocationSummary* locations =
1050 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001051 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001052 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001053 case Primitive::kPrimLong: {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001054 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
1055 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1056 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001057 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001058 break;
1059 }
1060
1061 case Primitive::kPrimBoolean:
1062 case Primitive::kPrimByte:
1063 case Primitive::kPrimChar:
1064 case Primitive::kPrimShort:
1065 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1066 break;
1067
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001068 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001069 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001070 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001071}
1072
1073void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1074 LocationSummary* locations = sub->GetLocations();
1075 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001076 case Primitive::kPrimInt: {
1077 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001078 __ sub(locations->Out().As<Register>(),
1079 locations->InAt(0).As<Register>(),
1080 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001081 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001082 __ AddConstant(locations->Out().As<Register>(),
1083 locations->InAt(0).As<Register>(),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001084 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
1085 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001086 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001087 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001088
1089 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001090 __ subs(locations->Out().AsRegisterPairLow<Register>(),
1091 locations->InAt(0).AsRegisterPairLow<Register>(),
1092 ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
1093 __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
1094 locations->InAt(0).AsRegisterPairHigh<Register>(),
1095 ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001096 break;
1097
1098 case Primitive::kPrimBoolean:
1099 case Primitive::kPrimByte:
1100 case Primitive::kPrimChar:
1101 case Primitive::kPrimShort:
1102 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
1103 break;
1104
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001105 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001107 }
1108}
1109
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001110void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001111 LocationSummary* locations =
1112 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001113 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001114 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1115 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1116 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001117}
1118
1119void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1120 InvokeRuntimeCallingConvention calling_convention;
1121 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
1122 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
1123
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001124 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001125 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001126 __ blx(LR);
1127
Nicolas Geoffray39468442014-09-02 15:17:15 +01001128 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001129 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001130}
1131
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001132void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001133 LocationSummary* locations =
1134 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001135 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1136 if (location.IsStackSlot()) {
1137 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1138 } else if (location.IsDoubleStackSlot()) {
1139 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001140 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001141 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001142}
1143
1144void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001145 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001146}
1147
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001148void LocationsBuilderARM::VisitNot(HNot* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001149 LocationSummary* locations =
1150 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001151 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001152 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001153}
1154
1155void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
1156 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001157 __ eor(locations->Out().As<Register>(),
1158 locations->InAt(0).As<Register>(), ShifterOperand(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001159}
1160
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001161void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001162 LocationSummary* locations =
1163 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001164 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1165 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001166 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001167}
1168
1169void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
1170 Label greater, done;
1171 LocationSummary* locations = compare->GetLocations();
1172 switch (compare->InputAt(0)->GetType()) {
1173 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001174 Register output = locations->Out().As<Register>();
1175 Location left = locations->InAt(0);
1176 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001177 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001178 __ cmp(left.AsRegisterPairHigh<Register>(),
1179 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001180 __ b(&less, LT);
1181 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001182 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1183 // the status flags.
1184 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001185 __ cmp(left.AsRegisterPairLow<Register>(),
1186 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001187 __ b(&done, EQ);
1188 __ b(&less, CC);
1189
1190 __ Bind(&greater);
1191 __ LoadImmediate(output, 1);
1192 __ b(&done);
1193
1194 __ Bind(&less);
1195 __ LoadImmediate(output, -1);
1196
1197 __ Bind(&done);
1198 break;
1199 }
1200 default:
1201 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1202 }
1203}
1204
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001205void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001206 LocationSummary* locations =
1207 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001208 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1209 locations->SetInAt(i, Location::Any());
1210 }
1211 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001212}
1213
1214void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001215 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001216}
1217
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001218void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001219 LocationSummary* locations =
1220 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001221 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
1222 bool dies_at_entry = !is_object_type;
1223 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
1224 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001225 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001226 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001227 locations->AddTemp(Location::RequiresRegister());
1228 locations->AddTemp(Location::RequiresRegister());
1229 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001230}
1231
1232void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1233 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001234 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001235 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001236 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001237
1238 switch (field_type) {
1239 case Primitive::kPrimBoolean:
1240 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001241 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001242 __ StoreToOffset(kStoreByte, value, obj, offset);
1243 break;
1244 }
1245
1246 case Primitive::kPrimShort:
1247 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001248 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001249 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1250 break;
1251 }
1252
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001253 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001254 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001255 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001256 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001257 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001258 Register temp = locations->GetTemp(0).As<Register>();
1259 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001260 codegen_->MarkGCCard(temp, card, obj, value);
1261 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001262 break;
1263 }
1264
1265 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001266 Location value = locations->InAt(1);
1267 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001268 break;
1269 }
1270
1271 case Primitive::kPrimFloat:
1272 case Primitive::kPrimDouble:
1273 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001274 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001275 case Primitive::kPrimVoid:
1276 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001277 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001278 }
1279}
1280
1281void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001282 LocationSummary* locations =
1283 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001284 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001285 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001286}
1287
1288void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1289 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001290 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001291 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1292
1293 switch (instruction->GetType()) {
1294 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001295 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001296 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1297 break;
1298 }
1299
1300 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001301 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001302 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1303 break;
1304 }
1305
1306 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001307 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001308 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1309 break;
1310 }
1311
1312 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001313 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001314 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1315 break;
1316 }
1317
1318 case Primitive::kPrimInt:
1319 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001320 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001321 __ LoadFromOffset(kLoadWord, out, obj, offset);
1322 break;
1323 }
1324
1325 case Primitive::kPrimLong: {
1326 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001327 Location out = locations->Out();
1328 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001329 break;
1330 }
1331
1332 case Primitive::kPrimFloat:
1333 case Primitive::kPrimDouble:
1334 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001335 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001336 case Primitive::kPrimVoid:
1337 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001338 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001339 }
1340}
1341
1342void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001343 LocationSummary* locations =
1344 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001345 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001346 if (instruction->HasUses()) {
1347 locations->SetOut(Location::SameAsFirstInput());
1348 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001349}
1350
1351void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001352 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001353 codegen_->AddSlowPath(slow_path);
1354
1355 LocationSummary* locations = instruction->GetLocations();
1356 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001357
1358 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001359 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001360 __ b(slow_path->GetEntryLabel(), EQ);
1361 } else {
1362 DCHECK(obj.IsConstant()) << obj;
1363 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1364 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001365 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001366}
1367
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001368void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001369 LocationSummary* locations =
1370 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001371 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1372 locations->SetInAt(
1373 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001374 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001375}
1376
1377void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
1378 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001379 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001380 Location index = locations->InAt(1);
1381
1382 switch (instruction->GetType()) {
1383 case Primitive::kPrimBoolean: {
1384 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001385 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001386 if (index.IsConstant()) {
1387 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1388 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1389 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001390 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001391 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
1392 }
1393 break;
1394 }
1395
1396 case Primitive::kPrimByte: {
1397 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001398 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001399 if (index.IsConstant()) {
1400 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1401 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1402 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001403 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001404 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
1405 }
1406 break;
1407 }
1408
1409 case Primitive::kPrimShort: {
1410 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001411 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001412 if (index.IsConstant()) {
1413 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1414 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1415 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001416 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001417 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
1418 }
1419 break;
1420 }
1421
1422 case Primitive::kPrimChar: {
1423 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001424 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001425 if (index.IsConstant()) {
1426 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1427 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1428 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001429 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001430 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
1431 }
1432 break;
1433 }
1434
1435 case Primitive::kPrimInt:
1436 case Primitive::kPrimNot: {
1437 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1438 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001439 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001440 if (index.IsConstant()) {
1441 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1442 __ LoadFromOffset(kLoadWord, out, obj, offset);
1443 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001444 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001445 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
1446 }
1447 break;
1448 }
1449
1450 case Primitive::kPrimLong: {
1451 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001452 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001453 if (index.IsConstant()) {
1454 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001455 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001456 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001457 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1458 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001459 }
1460 break;
1461 }
1462
1463 case Primitive::kPrimFloat:
1464 case Primitive::kPrimDouble:
1465 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001466 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001467 case Primitive::kPrimVoid:
1468 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001469 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001470 }
1471}
1472
1473void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001474 Primitive::Type value_type = instruction->GetComponentType();
1475 bool is_object = value_type == Primitive::kPrimNot;
1476 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1477 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1478 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001479 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001480 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1481 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1482 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001483 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001484 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
1485 locations->SetInAt(
1486 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
1487 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001488 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001489}
1490
1491void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
1492 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001493 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001494 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001495 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001496
1497 switch (value_type) {
1498 case Primitive::kPrimBoolean:
1499 case Primitive::kPrimByte: {
1500 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001501 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001502 if (index.IsConstant()) {
1503 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1504 __ StoreToOffset(kStoreByte, value, obj, offset);
1505 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001506 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001507 __ StoreToOffset(kStoreByte, value, IP, data_offset);
1508 }
1509 break;
1510 }
1511
1512 case Primitive::kPrimShort:
1513 case Primitive::kPrimChar: {
1514 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001515 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001516 if (index.IsConstant()) {
1517 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1518 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1519 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001520 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001521 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
1522 }
1523 break;
1524 }
1525
1526 case Primitive::kPrimInt: {
1527 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001528 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001529 if (index.IsConstant()) {
1530 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1531 __ StoreToOffset(kStoreWord, value, obj, offset);
1532 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001533 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001534 __ StoreToOffset(kStoreWord, value, IP, data_offset);
1535 }
1536 break;
1537 }
1538
1539 case Primitive::kPrimNot: {
1540 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001541 __ LoadFromOffset(kLoadWord, LR, TR, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001542 __ blx(LR);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001543 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001544 DCHECK(!codegen_->IsLeafMethod());
1545 break;
1546 }
1547
1548 case Primitive::kPrimLong: {
1549 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001550 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001551 if (index.IsConstant()) {
1552 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001553 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001554 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001555 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
1556 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001557 }
1558 break;
1559 }
1560
1561 case Primitive::kPrimFloat:
1562 case Primitive::kPrimDouble:
1563 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001564 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001565 case Primitive::kPrimVoid:
1566 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001567 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001568 }
1569}
1570
1571void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001572 LocationSummary* locations =
1573 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001574 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001575 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001576}
1577
1578void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
1579 LocationSummary* locations = instruction->GetLocations();
1580 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001581 Register obj = locations->InAt(0).As<Register>();
1582 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001583 __ LoadFromOffset(kLoadWord, out, obj, offset);
1584}
1585
1586void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001587 LocationSummary* locations =
1588 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001589 locations->SetInAt(0, Location::RequiresRegister());
1590 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001591 if (instruction->HasUses()) {
1592 locations->SetOut(Location::SameAsFirstInput());
1593 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001594}
1595
1596void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
1597 LocationSummary* locations = instruction->GetLocations();
1598 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001599 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001600 codegen_->AddSlowPath(slow_path);
1601
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001602 Register index = locations->InAt(0).As<Register>();
1603 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001604
1605 __ cmp(index, ShifterOperand(length));
1606 __ b(slow_path->GetEntryLabel(), CS);
1607}
1608
1609void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
1610 Label is_null;
1611 __ CompareAndBranchIfZero(value, &is_null);
1612 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
1613 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
1614 __ strb(card, Address(card, temp));
1615 __ Bind(&is_null);
1616}
1617
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001618void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
1619 temp->SetLocations(nullptr);
1620}
1621
1622void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
1623 // Nothing to do, this is driven by the code generator.
1624}
1625
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001626void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001627 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001628}
1629
1630void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001631 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1632}
1633
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001634void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
1635 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1636}
1637
1638void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001639 HBasicBlock* block = instruction->GetBlock();
1640 if (block->GetLoopInformation() != nullptr) {
1641 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
1642 // The back edge will generate the suspend check.
1643 return;
1644 }
1645 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
1646 // The goto will generate the suspend check.
1647 return;
1648 }
1649 GenerateSuspendCheck(instruction, nullptr);
1650}
1651
1652void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
1653 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001654 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001655 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001656 codegen_->AddSlowPath(slow_path);
1657
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001658 __ subs(R4, R4, ShifterOperand(1));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001659 if (successor == nullptr) {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001660 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001661 __ Bind(slow_path->GetReturnLabel());
1662 } else {
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001663 __ b(codegen_->GetLabelOf(successor), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001664 __ b(slow_path->GetEntryLabel());
1665 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00001666}
1667
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001668ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
1669 return codegen_->GetAssembler();
1670}
1671
1672void ParallelMoveResolverARM::EmitMove(size_t index) {
1673 MoveOperands* move = moves_.Get(index);
1674 Location source = move->GetSource();
1675 Location destination = move->GetDestination();
1676
1677 if (source.IsRegister()) {
1678 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001679 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001680 } else {
1681 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001682 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001683 SP, destination.GetStackIndex());
1684 }
1685 } else if (source.IsStackSlot()) {
1686 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001687 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001688 SP, source.GetStackIndex());
1689 } else {
1690 DCHECK(destination.IsStackSlot());
1691 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1692 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
1693 }
1694 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001695 DCHECK(source.IsConstant());
1696 DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
1697 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
1698 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001699 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001700 } else {
1701 DCHECK(destination.IsStackSlot());
1702 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001703 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001704 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001705 }
1706}
1707
1708void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
1709 __ Mov(IP, reg);
1710 __ LoadFromOffset(kLoadWord, reg, SP, mem);
1711 __ StoreToOffset(kStoreWord, IP, SP, mem);
1712}
1713
1714void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
1715 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
1716 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
1717 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
1718 SP, mem1 + stack_offset);
1719 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
1720 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
1721 SP, mem2 + stack_offset);
1722 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
1723}
1724
1725void ParallelMoveResolverARM::EmitSwap(size_t index) {
1726 MoveOperands* move = moves_.Get(index);
1727 Location source = move->GetSource();
1728 Location destination = move->GetDestination();
1729
1730 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001731 DCHECK_NE(source.As<Register>(), IP);
1732 DCHECK_NE(destination.As<Register>(), IP);
1733 __ Mov(IP, source.As<Register>());
1734 __ Mov(source.As<Register>(), destination.As<Register>());
1735 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001736 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001737 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001738 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001739 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001740 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1741 Exchange(source.GetStackIndex(), destination.GetStackIndex());
1742 } else {
1743 LOG(FATAL) << "Unimplemented";
1744 }
1745}
1746
1747void ParallelMoveResolverARM::SpillScratch(int reg) {
1748 __ Push(static_cast<Register>(reg));
1749}
1750
1751void ParallelMoveResolverARM::RestoreScratch(int reg) {
1752 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001753}
1754
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001755} // namespace arm
1756} // namespace art