blob: 7f3ebf46db4c2779d3e8c5f8f1bcbff39a65556d [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"
Roland Levillain647b96f2014-11-11 12:26:26 +000025#include "utils.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010026#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
Roland Levillain647b96f2014-11-11 12:26:26 +000028#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010029#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000030
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010032
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace arm {
34
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000035static DRegister FromLowSToD(SRegister reg) {
36 DCHECK_EQ(reg % 2, 0);
37 return static_cast<DRegister>(reg / 2);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010038}
39
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040static constexpr bool kExplicitStackOverflowCheck = false;
41
42static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
43static constexpr int kCurrentMethodStackOffset = 0;
44
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010045static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
46static constexpr size_t kRuntimeParameterCoreRegistersLength =
47 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000048static constexpr SRegister kRuntimeParameterFpuRegisters[] = { };
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000051class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010052 public:
53 InvokeRuntimeCallingConvention()
54 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010055 kRuntimeParameterCoreRegistersLength,
56 kRuntimeParameterFpuRegisters,
57 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010058
59 private:
60 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
61};
62
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010064#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010066class SlowPathCodeARM : public SlowPathCode {
67 public:
68 SlowPathCodeARM() : entry_label_(), exit_label_() {}
69
70 Label* GetEntryLabel() { return &entry_label_; }
71 Label* GetExitLabel() { return &exit_label_; }
72
73 private:
74 Label entry_label_;
75 Label exit_label_;
76
77 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
78};
79
80class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010082 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010083
84 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010085 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010086 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010087 arm_codegen->InvokeRuntime(
88 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010089 }
90
91 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010092 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010093 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
94};
95
Calin Juravled0d48522014-11-04 16:40:20 +000096class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
97 public:
98 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
99
100 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
101 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
102 __ Bind(GetEntryLabel());
103 arm_codegen->InvokeRuntime(
104 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
105 }
106
107 private:
108 HDivZeroCheck* const instruction_;
109 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
110};
111
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100112class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100113 public:
114 StackOverflowCheckSlowPathARM() {}
115
116 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
117 __ Bind(GetEntryLabel());
118 __ LoadFromOffset(kLoadWord, PC, TR,
119 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
120 }
121
122 private:
123 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
124};
125
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100126class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000127 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100128 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
129 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000130
131 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100132 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000133 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100134 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100135 arm_codegen->InvokeRuntime(
136 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100137 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100138 if (successor_ == nullptr) {
139 __ b(GetReturnLabel());
140 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100141 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100142 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143 }
144
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 Label* GetReturnLabel() {
146 DCHECK(successor_ == nullptr);
147 return &return_label_;
148 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000149
150 private:
151 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100152 // If not null, the block to branch to after the suspend check.
153 HBasicBlock* const successor_;
154
155 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156 Label return_label_;
157
158 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
159};
160
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100161class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100162 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100163 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
164 Location index_location,
165 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100166 : instruction_(instruction),
167 index_location_(index_location),
168 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100169
170 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100171 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100172 __ Bind(GetEntryLabel());
173 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100174 arm_codegen->Move32(
175 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
176 arm_codegen->Move32(
177 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
178 arm_codegen->InvokeRuntime(
179 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100180 }
181
182 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100183 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100184 const Location index_location_;
185 const Location length_location_;
186
187 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
188};
189
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000190class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100191 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000192 LoadClassSlowPathARM(HLoadClass* cls,
193 HInstruction* at,
194 uint32_t dex_pc,
195 bool do_clinit)
196 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
197 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
198 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100199
200 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000201 LocationSummary* locations = at_->GetLocations();
202
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100203 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
204 __ Bind(GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000205 codegen->SaveLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100206
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 int32_t entry_point_offset = do_clinit_
211 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
212 : QUICK_ENTRY_POINT(pInitializeType);
213 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
214
215 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000216 Location out = locations->Out();
217 if (out.IsValid()) {
218 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
220 }
221 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100222 __ b(GetExitLabel());
223 }
224
225 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226 // The class this slow path will load.
227 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000229 // The instruction where this slow path is happening.
230 // (Might be the load class or an initialization check).
231 HInstruction* const at_;
232
233 // The dex PC of `at_`.
234 const uint32_t dex_pc_;
235
236 // Whether to initialize the class.
237 const bool do_clinit_;
238
239 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100240};
241
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000242class LoadStringSlowPathARM : public SlowPathCodeARM {
243 public:
244 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
245
246 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
247 LocationSummary* locations = instruction_->GetLocations();
248 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
249
250 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
251 __ Bind(GetEntryLabel());
252 codegen->SaveLiveRegisters(locations);
253
254 InvokeRuntimeCallingConvention calling_convention;
255 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0));
256 __ LoadImmediate(calling_convention.GetRegisterAt(1), instruction_->GetStringIndex());
257 arm_codegen->InvokeRuntime(
258 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
259 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
260
261 codegen->RestoreLiveRegisters(locations);
262 __ b(GetExitLabel());
263 }
264
265 private:
266 HLoadString* const instruction_;
267
268 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
269};
270
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000271class TypeCheckSlowPathARM : public SlowPathCodeARM {
272 public:
273 explicit TypeCheckSlowPathARM(HTypeCheck* instruction, Location object_class)
274 : instruction_(instruction),
275 object_class_(object_class) {}
276
277 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
278 LocationSummary* locations = instruction_->GetLocations();
279 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
280
281 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
282 __ Bind(GetEntryLabel());
283 codegen->SaveLiveRegisters(locations);
284
285 // We're moving two locations to locations that could overlap, so we need a parallel
286 // move resolver.
287 InvokeRuntimeCallingConvention calling_convention;
288 MoveOperands move1(locations->InAt(1),
289 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
290 nullptr);
291 MoveOperands move2(object_class_,
292 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
293 nullptr);
294 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
295 parallel_move.AddMove(&move1);
296 parallel_move.AddMove(&move2);
297 arm_codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
298
299 arm_codegen->InvokeRuntime(
300 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, instruction_->GetDexPc());
301 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
302
303 codegen->RestoreLiveRegisters(locations);
304 __ b(GetExitLabel());
305 }
306
307 private:
308 HTypeCheck* const instruction_;
309 const Location object_class_;
310
311 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
312};
313
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000314#undef __
315
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100316#undef __
317#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700318
319inline Condition ARMCondition(IfCondition cond) {
320 switch (cond) {
321 case kCondEQ: return EQ;
322 case kCondNE: return NE;
323 case kCondLT: return LT;
324 case kCondLE: return LE;
325 case kCondGT: return GT;
326 case kCondGE: return GE;
327 default:
328 LOG(FATAL) << "Unknown if condition";
329 }
330 return EQ; // Unreachable.
331}
332
333inline Condition ARMOppositeCondition(IfCondition cond) {
334 switch (cond) {
335 case kCondEQ: return NE;
336 case kCondNE: return EQ;
337 case kCondLT: return GE;
338 case kCondLE: return GT;
339 case kCondGT: return LE;
340 case kCondGE: return LT;
341 default:
342 LOG(FATAL) << "Unknown if condition";
343 }
344 return EQ; // Unreachable.
345}
346
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100347void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
348 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
349}
350
351void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000352 stream << ArmManagedRegister::FromSRegister(SRegister(reg));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100353}
354
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100355size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
356 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
357 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100358}
359
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100360size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
361 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
362 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100363}
364
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100365CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000366 : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100367 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100368 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100369 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100370 move_resolver_(graph->GetArena(), this),
371 assembler_(true) {}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100372
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100373size_t CodeGeneratorARM::FrameEntrySpillSize() const {
374 return kNumberOfPushedRegistersAtEntry * kArmWordSize;
375}
376
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100377Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100378 switch (type) {
379 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100380 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100381 ArmManagedRegister pair =
382 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100383 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
384 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
385
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100386 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
387 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100388 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100389 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100390 }
391
392 case Primitive::kPrimByte:
393 case Primitive::kPrimBoolean:
394 case Primitive::kPrimChar:
395 case Primitive::kPrimShort:
396 case Primitive::kPrimInt:
397 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100398 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100399 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100400 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
401 ArmManagedRegister current =
402 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
403 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100404 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100405 }
406 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100407 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100408 }
409
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000410 case Primitive::kPrimFloat: {
411 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100412 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100413 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100414
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000415 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000416 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
417 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000418 return Location::FpuRegisterPairLocation(reg, reg + 1);
419 }
420
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100421 case Primitive::kPrimVoid:
422 LOG(FATAL) << "Unreachable type " << type;
423 }
424
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100425 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100426}
427
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100428void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100429 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100430 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100431
432 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100433 blocked_core_registers_[SP] = true;
434 blocked_core_registers_[LR] = true;
435 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100436
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100437 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100438 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100439
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100440 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100441 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100442
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100443 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100444 // We always save and restore R6 and R7 to make sure we can use three
445 // register pairs for long operations.
Nicolas Geoffray44b819e2014-11-06 12:00:54 +0000446 blocked_core_registers_[R4] = true;
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100447 blocked_core_registers_[R5] = true;
448 blocked_core_registers_[R8] = true;
449 blocked_core_registers_[R10] = true;
450 blocked_core_registers_[R11] = true;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100451
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000452 blocked_fpu_registers_[S16] = true;
453 blocked_fpu_registers_[S17] = true;
454 blocked_fpu_registers_[S18] = true;
455 blocked_fpu_registers_[S19] = true;
456 blocked_fpu_registers_[S20] = true;
457 blocked_fpu_registers_[S21] = true;
458 blocked_fpu_registers_[S22] = true;
459 blocked_fpu_registers_[S23] = true;
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000460 blocked_fpu_registers_[S24] = true;
461 blocked_fpu_registers_[S25] = true;
462 blocked_fpu_registers_[S26] = true;
463 blocked_fpu_registers_[S27] = true;
464 blocked_fpu_registers_[S28] = true;
465 blocked_fpu_registers_[S29] = true;
466 blocked_fpu_registers_[S30] = true;
467 blocked_fpu_registers_[S31] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100468
469 UpdateBlockedPairRegisters();
470}
471
472void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
473 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
474 ArmManagedRegister current =
475 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
476 if (blocked_core_registers_[current.AsRegisterPairLow()]
477 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
478 blocked_register_pairs_[i] = true;
479 }
480 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100481}
482
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100483InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
484 : HGraphVisitor(graph),
485 assembler_(codegen->GetAssembler()),
486 codegen_(codegen) {}
487
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000488void CodeGeneratorARM::GenerateFrameEntry() {
Dave Allison648d7112014-07-25 16:15:27 -0700489 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100490 if (!skip_overflow_check) {
491 if (kExplicitStackOverflowCheck) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100492 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100493 AddSlowPath(slow_path);
494
495 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
496 __ cmp(SP, ShifterOperand(IP));
497 __ b(slow_path->GetEntryLabel(), CC);
498 } else {
499 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100500 __ LoadFromOffset(kLoadWord, IP, IP, 0);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100501 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100502 }
503 }
504
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100505 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7);
506 __ PushList(1 << LR | 1 << R6 | 1 << R7);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000507
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100508 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100509 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100510 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000511}
512
513void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100514 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100515 __ PopList(1 << PC | 1 << R6 | 1 << R7);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000516}
517
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100518void CodeGeneratorARM::Bind(HBasicBlock* block) {
519 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000520}
521
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100522Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
523 switch (load->GetType()) {
524 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100525 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100526 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
527 break;
528
529 case Primitive::kPrimInt:
530 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100531 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100532 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100533
534 case Primitive::kPrimBoolean:
535 case Primitive::kPrimByte:
536 case Primitive::kPrimChar:
537 case Primitive::kPrimShort:
538 case Primitive::kPrimVoid:
539 LOG(FATAL) << "Unexpected type " << load->GetType();
540 }
541
542 LOG(FATAL) << "Unreachable";
543 return Location();
544}
545
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100546Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
547 switch (type) {
548 case Primitive::kPrimBoolean:
549 case Primitive::kPrimByte:
550 case Primitive::kPrimChar:
551 case Primitive::kPrimShort:
552 case Primitive::kPrimInt:
553 case Primitive::kPrimNot: {
554 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000555 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100556 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100557 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100558 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000559 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100560 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100561 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100562
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000563 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100564 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000565 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100566 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000567 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100568 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100569 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair(
570 calling_convention.GetRegisterPairAt(index));
571 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100572 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000573 return Location::QuickParameter(index, stack_index);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100574 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000575 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
576 }
577 }
578
579 case Primitive::kPrimFloat: {
580 uint32_t stack_index = stack_index_++;
581 if (float_index_ % 2 == 0) {
582 float_index_ = std::max(double_index_, float_index_);
583 }
584 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
585 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
586 } else {
587 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
588 }
589 }
590
591 case Primitive::kPrimDouble: {
592 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
593 uint32_t stack_index = stack_index_;
594 stack_index_ += 2;
595 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
596 uint32_t index = double_index_;
597 double_index_ += 2;
598 return Location::FpuRegisterPairLocation(
599 calling_convention.GetFpuRegisterAt(index),
600 calling_convention.GetFpuRegisterAt(index + 1));
601 } else {
602 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100603 }
604 }
605
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100606 case Primitive::kPrimVoid:
607 LOG(FATAL) << "Unexpected parameter type " << type;
608 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100609 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100610 return Location();
611}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100612
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000613Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
614 switch (type) {
615 case Primitive::kPrimBoolean:
616 case Primitive::kPrimByte:
617 case Primitive::kPrimChar:
618 case Primitive::kPrimShort:
619 case Primitive::kPrimInt:
620 case Primitive::kPrimNot: {
621 return Location::RegisterLocation(R0);
622 }
623
624 case Primitive::kPrimFloat: {
625 return Location::FpuRegisterLocation(S0);
626 }
627
628 case Primitive::kPrimLong: {
629 return Location::RegisterPairLocation(R0, R1);
630 }
631
632 case Primitive::kPrimDouble: {
633 return Location::FpuRegisterPairLocation(S0, S1);
634 }
635
636 case Primitive::kPrimVoid:
637 return Location();
638 }
639 UNREACHABLE();
640 return Location();
641}
642
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100643void CodeGeneratorARM::Move32(Location destination, Location source) {
644 if (source.Equals(destination)) {
645 return;
646 }
647 if (destination.IsRegister()) {
648 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100649 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100650 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000651 __ vmovrs(destination.As<Register>(), source.As<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100652 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100653 __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100654 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100655 } else if (destination.IsFpuRegister()) {
656 if (source.IsRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000657 __ vmovsr(destination.As<SRegister>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100658 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000659 __ vmovs(destination.As<SRegister>(), source.As<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100660 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000661 __ LoadSFromOffset(destination.As<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100662 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100663 } else {
664 DCHECK(destination.IsStackSlot());
665 if (source.IsRegister()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100666 __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100667 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000668 __ StoreSToOffset(source.As<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100669 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100670 DCHECK(source.IsStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100671 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
672 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100673 }
674 }
675}
676
677void CodeGeneratorARM::Move64(Location destination, Location source) {
678 if (source.Equals(destination)) {
679 return;
680 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100681 if (destination.IsRegisterPair()) {
682 if (source.IsRegisterPair()) {
683 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
684 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100685 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000686 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100687 } else if (source.IsQuickParameter()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000688 uint16_t register_index = source.GetQuickParameterRegisterIndex();
689 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100690 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100691 __ Mov(destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000692 calling_convention.GetRegisterAt(register_index));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100693 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000694 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100695 } else {
696 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100697 if (destination.AsRegisterPairLow<Register>() == R1) {
698 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100699 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex());
700 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100701 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100702 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100703 SP, source.GetStackIndex());
704 }
705 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000706 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100707 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000708 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
709 SP,
710 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100711 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000712 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100713 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100714 } else if (destination.IsQuickParameter()) {
715 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000716 uint16_t register_index = destination.GetQuickParameterRegisterIndex();
717 uint16_t stack_index = destination.GetQuickParameterStackIndex();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100718 if (source.IsRegisterPair()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000719 __ Mov(calling_convention.GetRegisterAt(register_index),
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100720 source.AsRegisterPairLow<Register>());
721 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000722 SP, calling_convention.GetStackOffsetOf(stack_index + 1));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100723 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000724 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100725 } else {
726 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000727 __ LoadFromOffset(
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000728 kLoadWord, calling_convention.GetRegisterAt(register_index), SP, source.GetStackIndex());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100729 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000730 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(stack_index + 1));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731 }
732 } else {
733 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100734 if (source.IsRegisterPair()) {
735 if (source.AsRegisterPairLow<Register>() == R1) {
736 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100737 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
738 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100739 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100740 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 SP, destination.GetStackIndex());
742 }
743 } else if (source.IsQuickParameter()) {
744 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000745 uint16_t register_index = source.GetQuickParameterRegisterIndex();
746 uint16_t stack_index = source.GetQuickParameterStackIndex();
747 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(register_index),
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100748 SP, destination.GetStackIndex());
749 __ LoadFromOffset(kLoadWord, R0,
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000750 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100751 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000752 } else if (source.IsFpuRegisterPair()) {
753 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
754 SP,
755 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100756 } else {
757 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100758 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
759 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
760 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
761 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100762 }
763 }
764}
765
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100766void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100767 LocationSummary* locations = instruction->GetLocations();
768 if (locations != nullptr && locations->Out().Equals(location)) {
769 return;
770 }
771
Roland Levillain476df552014-10-09 17:51:36 +0100772 if (instruction->IsIntConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100773 int32_t value = instruction->AsIntConstant()->GetValue();
774 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100775 __ LoadImmediate(location.As<Register>(), value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100776 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100777 DCHECK(location.IsStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100778 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100779 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100780 }
Roland Levillain476df552014-10-09 17:51:36 +0100781 } else if (instruction->IsLongConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100782 int64_t value = instruction->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100783 if (location.IsRegisterPair()) {
784 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
785 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100787 DCHECK(location.IsDoubleStackSlot());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100788 __ LoadImmediate(IP, Low32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100789 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100790 __ LoadImmediate(IP, High32Bits(value));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100791 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100792 }
Roland Levillain476df552014-10-09 17:51:36 +0100793 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100794 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
795 switch (instruction->GetType()) {
796 case Primitive::kPrimBoolean:
797 case Primitive::kPrimByte:
798 case Primitive::kPrimChar:
799 case Primitive::kPrimShort:
800 case Primitive::kPrimInt:
801 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100802 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100803 Move32(location, Location::StackSlot(stack_slot));
804 break;
805
806 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100807 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 Move64(location, Location::DoubleStackSlot(stack_slot));
809 break;
810
811 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100812 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000814 } else if (instruction->IsTemporary()) {
815 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
816 Move32(location, temp_location);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000817 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100818 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100819 switch (instruction->GetType()) {
820 case Primitive::kPrimBoolean:
821 case Primitive::kPrimByte:
822 case Primitive::kPrimChar:
823 case Primitive::kPrimShort:
824 case Primitive::kPrimNot:
825 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100826 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100827 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100828 break;
829
830 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100831 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100832 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 break;
834
835 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100836 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100837 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000838 }
839}
840
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100841void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
842 HInstruction* instruction,
843 uint32_t dex_pc) {
844 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
845 __ blx(LR);
846 RecordPcInfo(instruction, dex_pc);
847 DCHECK(instruction->IsSuspendCheck()
848 || instruction->IsBoundsCheck()
849 || instruction->IsNullCheck()
Calin Juravled0d48522014-11-04 16:40:20 +0000850 || instruction->IsDivZeroCheck()
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100851 || !IsLeafMethod());
852}
853
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000854void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000855 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000856}
857
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000858void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000859 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100860 DCHECK(!successor->IsExitBlock());
861
862 HBasicBlock* block = got->GetBlock();
863 HInstruction* previous = got->GetPrevious();
864
865 HLoopInformation* info = block->GetLoopInformation();
866 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
867 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
868 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
869 return;
870 }
871
872 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
873 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
874 }
875 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000876 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000877 }
878}
879
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000880void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000881 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000882}
883
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000884void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700885 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000886 if (kIsDebugBuild) {
887 __ Comment("Unreachable");
888 __ bkpt(0);
889 }
890}
891
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000892void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100893 LocationSummary* locations =
894 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100895 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100896 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100897 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100898 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000899}
900
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000901void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700902 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100903 if (cond->IsIntConstant()) {
904 // Constant condition, statically compared against 1.
905 int32_t cond_value = cond->AsIntConstant()->GetValue();
906 if (cond_value == 1) {
907 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
908 if_instr->IfTrueSuccessor())) {
909 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100910 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100911 return;
912 } else {
913 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100914 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100915 } else {
916 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
917 // Condition has been materialized, compare the output to 0
918 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
919 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
920 ShifterOperand(0));
921 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
922 } else {
923 // Condition has not been materialized, use its inputs as the
924 // comparison and its condition as the branch condition.
925 LocationSummary* locations = cond->GetLocations();
926 if (locations->InAt(1).IsRegister()) {
927 __ cmp(locations->InAt(0).As<Register>(),
928 ShifterOperand(locations->InAt(1).As<Register>()));
929 } else {
930 DCHECK(locations->InAt(1).IsConstant());
931 int32_t value =
932 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
933 ShifterOperand operand;
934 if (ShifterOperand::CanHoldArm(value, &operand)) {
935 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
936 } else {
937 Register temp = IP;
938 __ LoadImmediate(temp, value);
939 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
940 }
941 }
942 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
943 ARMCondition(cond->AsCondition()->GetCondition()));
944 }
Dave Allison20dfc792014-06-16 20:44:29 -0700945 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100946 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
947 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700948 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000949 }
950}
951
Dave Allison20dfc792014-06-16 20:44:29 -0700952
953void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100954 LocationSummary* locations =
955 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100956 locations->SetInAt(0, Location::RequiresRegister());
957 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100958 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100959 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100960 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000961}
962
Dave Allison20dfc792014-06-16 20:44:29 -0700963void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100964 if (!comp->NeedsMaterialization()) return;
965
966 LocationSummary* locations = comp->GetLocations();
967 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100968 __ cmp(locations->InAt(0).As<Register>(),
969 ShifterOperand(locations->InAt(1).As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100970 } else {
971 DCHECK(locations->InAt(1).IsConstant());
972 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
973 ShifterOperand operand;
974 if (ShifterOperand::CanHoldArm(value, &operand)) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100975 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100976 } else {
977 Register temp = IP;
978 __ LoadImmediate(temp, value);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100979 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100980 }
Dave Allison20dfc792014-06-16 20:44:29 -0700981 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100982 __ it(ARMCondition(comp->GetCondition()), kItElse);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100983 __ mov(locations->Out().As<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100984 ARMCondition(comp->GetCondition()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100985 __ mov(locations->Out().As<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100986 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -0700987}
988
989void LocationsBuilderARM::VisitEqual(HEqual* comp) {
990 VisitCondition(comp);
991}
992
993void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
994 VisitCondition(comp);
995}
996
997void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
998 VisitCondition(comp);
999}
1000
1001void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1002 VisitCondition(comp);
1003}
1004
1005void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1006 VisitCondition(comp);
1007}
1008
1009void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1010 VisitCondition(comp);
1011}
1012
1013void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1014 VisitCondition(comp);
1015}
1016
1017void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1018 VisitCondition(comp);
1019}
1020
1021void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1022 VisitCondition(comp);
1023}
1024
1025void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1026 VisitCondition(comp);
1027}
1028
1029void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1030 VisitCondition(comp);
1031}
1032
1033void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1034 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001035}
1036
1037void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001038 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001039}
1040
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001041void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1042 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001043}
1044
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001045void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001046 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001047}
1048
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001049void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001050 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001051 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001052}
1053
1054void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001055 LocationSummary* locations =
1056 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001057 switch (store->InputAt(1)->GetType()) {
1058 case Primitive::kPrimBoolean:
1059 case Primitive::kPrimByte:
1060 case Primitive::kPrimChar:
1061 case Primitive::kPrimShort:
1062 case Primitive::kPrimInt:
1063 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001064 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001065 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1066 break;
1067
1068 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001069 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001070 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1071 break;
1072
1073 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001074 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001075 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001076}
1077
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001078void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001079 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001080}
1081
1082void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001083 LocationSummary* locations =
1084 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001085 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001086}
1087
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001088void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001089 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001090 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001091}
1092
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001093void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001094 LocationSummary* locations =
1095 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001096 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097}
1098
1099void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1100 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001101 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001102}
1103
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001104void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1105 LocationSummary* locations =
1106 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1107 locations->SetOut(Location::ConstantLocation(constant));
1108}
1109
1110void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1111 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001112 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001113}
1114
1115void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1116 LocationSummary* locations =
1117 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1118 locations->SetOut(Location::ConstantLocation(constant));
1119}
1120
1121void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1122 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001123 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001124}
1125
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001126void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001127 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001128}
1129
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001130void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001131 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001132 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001133}
1134
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001135void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001136 LocationSummary* locations =
1137 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001138 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001139}
1140
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001141void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001142 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001143 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001144}
1145
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001146void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001147 HandleInvoke(invoke);
1148}
1149
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001150void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001151 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001152}
1153
1154void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001155 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001156
1157 // TODO: Implement all kinds of calls:
1158 // 1) boot -> boot
1159 // 2) app -> boot
1160 // 3) app -> app
1161 //
1162 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1163
1164 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001165 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001166 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001167 __ LoadFromOffset(
1168 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001169 // temp = temp[index_in_cache]
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001170 __ LoadFromOffset(
1171 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache()));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001172 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001173 __ LoadFromOffset(kLoadWord, LR, temp,
1174 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001175 // LR()
1176 __ blx(LR);
1177
1178 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1179 DCHECK(!codegen_->IsLeafMethod());
1180}
1181
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001182void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001183 LocationSummary* locations =
1184 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001185 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001186
1187 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001188 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001189 HInstruction* input = invoke->InputAt(i);
1190 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1191 }
1192
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001193 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001194}
1195
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001196void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1197 HandleInvoke(invoke);
1198}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001199
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001200void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001201 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001202 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1203 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1204 LocationSummary* locations = invoke->GetLocations();
1205 Location receiver = locations->InAt(0);
1206 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1207 // temp = object->GetClass();
1208 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001209 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1210 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001211 } else {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001212 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001213 }
1214 // temp = temp->GetMethodAt(method_offset);
1215 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001216 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001217 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001218 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001219 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001220 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001221 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001222 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001223}
1224
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001225void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1226 HandleInvoke(invoke);
1227 // Add the hidden argument.
1228 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1229}
1230
1231void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1232 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1233 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
1234 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1235 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1236 LocationSummary* locations = invoke->GetLocations();
1237 Location receiver = locations->InAt(0);
1238 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1239
1240 // Set the hidden argument.
1241 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).As<Register>(), invoke->GetDexMethodIndex());
1242
1243 // temp = object->GetClass();
1244 if (receiver.IsStackSlot()) {
1245 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1246 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1247 } else {
1248 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset);
1249 }
1250 // temp = temp->GetImtEntryAt(method_offset);
1251 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
1252 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1253 // LR = temp->GetEntryPoint();
1254 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1255 // LR();
1256 __ blx(LR);
1257 DCHECK(!codegen_->IsLeafMethod());
1258 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1259}
1260
Roland Levillain88cb1752014-10-20 16:36:47 +01001261void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1262 LocationSummary* locations =
1263 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1264 switch (neg->GetResultType()) {
1265 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001266 case Primitive::kPrimLong: {
1267 bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong);
Roland Levillain88cb1752014-10-20 16:36:47 +01001268 locations->SetInAt(0, Location::RequiresRegister());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001269 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Roland Levillain88cb1752014-10-20 16:36:47 +01001270 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001271 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001272
Roland Levillain88cb1752014-10-20 16:36:47 +01001273 case Primitive::kPrimFloat:
1274 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001275 locations->SetInAt(0, Location::RequiresFpuRegister());
1276 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001277 break;
1278
1279 default:
1280 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1281 }
1282}
1283
1284void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1285 LocationSummary* locations = neg->GetLocations();
1286 Location out = locations->Out();
1287 Location in = locations->InAt(0);
1288 switch (neg->GetResultType()) {
1289 case Primitive::kPrimInt:
1290 DCHECK(in.IsRegister());
Roland Levillainb762d2e2014-10-22 10:11:06 +01001291 __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001292 break;
1293
1294 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001295 DCHECK(in.IsRegisterPair());
1296 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1297 __ rsbs(out.AsRegisterPairLow<Register>(),
1298 in.AsRegisterPairLow<Register>(),
1299 ShifterOperand(0));
1300 // We cannot emit an RSC (Reverse Subtract with Carry)
1301 // instruction here, as it does not exist in the Thumb-2
1302 // instruction set. We use the following approach
1303 // using SBC and SUB instead.
1304 //
1305 // out.hi = -C
1306 __ sbc(out.AsRegisterPairHigh<Register>(),
1307 out.AsRegisterPairHigh<Register>(),
1308 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1309 // out.hi = out.hi - in.hi
1310 __ sub(out.AsRegisterPairHigh<Register>(),
1311 out.AsRegisterPairHigh<Register>(),
1312 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1313 break;
1314
Roland Levillain88cb1752014-10-20 16:36:47 +01001315 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001316 DCHECK(in.IsFpuRegister());
1317 __ vnegs(out.As<SRegister>(), in.As<SRegister>());
1318 break;
1319
Roland Levillain88cb1752014-10-20 16:36:47 +01001320 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001321 DCHECK(in.IsFpuRegisterPair());
1322 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1323 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001324 break;
1325
1326 default:
1327 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1328 }
1329}
1330
Roland Levillaindff1f282014-11-05 14:15:05 +00001331void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
1332 LocationSummary* locations =
1333 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1334 Primitive::Type result_type = conversion->GetResultType();
1335 Primitive::Type input_type = conversion->GetInputType();
1336 switch (result_type) {
Roland Levillain647b96f2014-11-11 12:26:26 +00001337 case Primitive::kPrimInt:
1338 switch (input_type) {
1339 case Primitive::kPrimLong:
1340 // long-to-int conversion.
1341 locations->SetInAt(0, Location::Any());
1342 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1343 break;
1344
1345 case Primitive::kPrimFloat:
1346 case Primitive::kPrimDouble:
1347 LOG(FATAL) << "Type conversion from " << input_type
1348 << " to " << result_type << " not yet implemented";
1349 break;
1350
1351 default:
1352 LOG(FATAL) << "Unexpected type conversion from " << input_type
1353 << " to " << result_type;
1354 }
1355 break;
1356
Roland Levillaindff1f282014-11-05 14:15:05 +00001357 case Primitive::kPrimLong:
1358 switch (input_type) {
1359 case Primitive::kPrimByte:
1360 case Primitive::kPrimShort:
1361 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001362 case Primitive::kPrimChar:
Roland Levillaindff1f282014-11-05 14:15:05 +00001363 // int-to-long conversion.
1364 locations->SetInAt(0, Location::RequiresRegister());
1365 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1366 break;
1367
1368 case Primitive::kPrimFloat:
1369 case Primitive::kPrimDouble:
1370 LOG(FATAL) << "Type conversion from " << input_type << " to "
1371 << result_type << " not yet implemented";
1372 break;
1373
1374 default:
1375 LOG(FATAL) << "Unexpected type conversion from " << input_type
1376 << " to " << result_type;
1377 }
1378 break;
1379
Roland Levillaindff1f282014-11-05 14:15:05 +00001380 case Primitive::kPrimFloat:
1381 case Primitive::kPrimDouble:
1382 LOG(FATAL) << "Type conversion from " << input_type
1383 << " to " << result_type << " not yet implemented";
1384 break;
1385
1386 default:
1387 LOG(FATAL) << "Unexpected type conversion from " << input_type
1388 << " to " << result_type;
1389 }
1390}
1391
1392void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1393 LocationSummary* locations = conversion->GetLocations();
1394 Location out = locations->Out();
1395 Location in = locations->InAt(0);
1396 Primitive::Type result_type = conversion->GetResultType();
1397 Primitive::Type input_type = conversion->GetInputType();
1398 switch (result_type) {
Roland Levillain647b96f2014-11-11 12:26:26 +00001399 case Primitive::kPrimInt:
1400 switch (input_type) {
1401 case Primitive::kPrimLong:
1402 // long-to-int conversion.
1403 DCHECK(out.IsRegister());
1404 if (in.IsRegisterPair()) {
1405 __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>());
1406 } else if (in.IsDoubleStackSlot()) {
1407 __ LoadFromOffset(kLoadWord, out.As<Register>(), SP, in.GetStackIndex());
1408 } else {
1409 DCHECK(in.IsConstant());
1410 DCHECK(in.GetConstant()->IsLongConstant());
1411 __ LoadImmediate(out.As<Register>(),
1412 Low32Bits(in.GetConstant()->AsLongConstant()->GetValue()));
1413 }
1414 break;
1415
1416 case Primitive::kPrimFloat:
1417 case Primitive::kPrimDouble:
1418 LOG(FATAL) << "Type conversion from " << input_type
1419 << " to " << result_type << " not yet implemented";
1420 break;
1421
1422 default:
1423 LOG(FATAL) << "Unexpected type conversion from " << input_type
1424 << " to " << result_type;
1425 }
1426 break;
1427
Roland Levillaindff1f282014-11-05 14:15:05 +00001428 case Primitive::kPrimLong:
1429 switch (input_type) {
1430 case Primitive::kPrimByte:
1431 case Primitive::kPrimShort:
1432 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001433 case Primitive::kPrimChar:
Roland Levillaindff1f282014-11-05 14:15:05 +00001434 // int-to-long conversion.
1435 DCHECK(out.IsRegisterPair());
1436 DCHECK(in.IsRegister());
1437 __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>());
1438 // Sign extension.
1439 __ Asr(out.AsRegisterPairHigh<Register>(),
1440 out.AsRegisterPairLow<Register>(),
1441 31);
1442 break;
1443
1444 case Primitive::kPrimFloat:
1445 case Primitive::kPrimDouble:
1446 LOG(FATAL) << "Type conversion from " << input_type << " to "
1447 << result_type << " not yet implemented";
1448 break;
1449
1450 default:
1451 LOG(FATAL) << "Unexpected type conversion from " << input_type
1452 << " to " << result_type;
1453 }
1454 break;
1455
Roland Levillaindff1f282014-11-05 14:15:05 +00001456 case Primitive::kPrimFloat:
1457 case Primitive::kPrimDouble:
1458 LOG(FATAL) << "Type conversion from " << input_type
1459 << " to " << result_type << " not yet implemented";
1460 break;
1461
1462 default:
1463 LOG(FATAL) << "Unexpected type conversion from " << input_type
1464 << " to " << result_type;
1465 }
1466}
1467
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001468void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001469 LocationSummary* locations =
1470 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001471 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001472 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001473 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001474 bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong);
1475 locations->SetInAt(0, Location::RequiresRegister());
1476 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1477 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001478 break;
1479 }
1480
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001481 case Primitive::kPrimFloat:
1482 case Primitive::kPrimDouble: {
1483 locations->SetInAt(0, Location::RequiresFpuRegister());
1484 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001485 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001486 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001487 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001488
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001489 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001490 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001491 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001492}
1493
1494void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1495 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001496 Location out = locations->Out();
1497 Location first = locations->InAt(0);
1498 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001499 switch (add->GetResultType()) {
1500 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001501 if (second.IsRegister()) {
1502 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001503 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001504 __ AddConstant(out.As<Register>(),
1505 first.As<Register>(),
1506 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001507 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001508 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001509
1510 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001511 __ adds(out.AsRegisterPairLow<Register>(),
1512 first.AsRegisterPairLow<Register>(),
1513 ShifterOperand(second.AsRegisterPairLow<Register>()));
1514 __ adc(out.AsRegisterPairHigh<Register>(),
1515 first.AsRegisterPairHigh<Register>(),
1516 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001517 break;
1518
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001519 case Primitive::kPrimFloat:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001520 __ vadds(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001521 break;
1522
1523 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001524 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1525 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1526 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001527 break;
1528
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001529 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001530 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001531 }
1532}
1533
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001534void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001535 LocationSummary* locations =
1536 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001537 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001538 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001539 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001540 bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong);
1541 locations->SetInAt(0, Location::RequiresRegister());
1542 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
1543 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001544 break;
1545 }
Calin Juravle11351682014-10-23 15:38:15 +01001546 case Primitive::kPrimFloat:
1547 case Primitive::kPrimDouble: {
1548 locations->SetInAt(0, Location::RequiresFpuRegister());
1549 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001550 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001551 break;
Calin Juravle11351682014-10-23 15:38:15 +01001552 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001553 default:
Calin Juravle11351682014-10-23 15:38:15 +01001554 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001555 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001556}
1557
1558void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1559 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001560 Location out = locations->Out();
1561 Location first = locations->InAt(0);
1562 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001563 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001564 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001565 if (second.IsRegister()) {
1566 __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001567 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001568 __ AddConstant(out.As<Register>(),
1569 first.As<Register>(),
1570 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001571 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001572 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001573 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001574
Calin Juravle11351682014-10-23 15:38:15 +01001575 case Primitive::kPrimLong: {
1576 __ subs(out.AsRegisterPairLow<Register>(),
1577 first.AsRegisterPairLow<Register>(),
1578 ShifterOperand(second.AsRegisterPairLow<Register>()));
1579 __ sbc(out.AsRegisterPairHigh<Register>(),
1580 first.AsRegisterPairHigh<Register>(),
1581 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001582 break;
Calin Juravle11351682014-10-23 15:38:15 +01001583 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001584
Calin Juravle11351682014-10-23 15:38:15 +01001585 case Primitive::kPrimFloat: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001586 __ vsubs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001587 break;
Calin Juravle11351682014-10-23 15:38:15 +01001588 }
1589
1590 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001591 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1592 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1593 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01001594 break;
1595 }
1596
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001597
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001598 default:
Calin Juravle11351682014-10-23 15:38:15 +01001599 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001600 }
1601}
1602
Calin Juravle34bacdf2014-10-07 20:23:36 +01001603void LocationsBuilderARM::VisitMul(HMul* mul) {
1604 LocationSummary* locations =
1605 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1606 switch (mul->GetResultType()) {
1607 case Primitive::kPrimInt:
1608 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001609 locations->SetInAt(0, Location::RequiresRegister());
1610 locations->SetInAt(1, Location::RequiresRegister());
1611 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001612 break;
1613 }
1614
Calin Juravleb5bfa962014-10-21 18:02:24 +01001615 case Primitive::kPrimFloat:
1616 case Primitive::kPrimDouble: {
1617 locations->SetInAt(0, Location::RequiresFpuRegister());
1618 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001619 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001620 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001621 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001622
1623 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001624 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001625 }
1626}
1627
1628void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
1629 LocationSummary* locations = mul->GetLocations();
1630 Location out = locations->Out();
1631 Location first = locations->InAt(0);
1632 Location second = locations->InAt(1);
1633 switch (mul->GetResultType()) {
1634 case Primitive::kPrimInt: {
1635 __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>());
1636 break;
1637 }
1638 case Primitive::kPrimLong: {
1639 Register out_hi = out.AsRegisterPairHigh<Register>();
1640 Register out_lo = out.AsRegisterPairLow<Register>();
1641 Register in1_hi = first.AsRegisterPairHigh<Register>();
1642 Register in1_lo = first.AsRegisterPairLow<Register>();
1643 Register in2_hi = second.AsRegisterPairHigh<Register>();
1644 Register in2_lo = second.AsRegisterPairLow<Register>();
1645
1646 // Extra checks to protect caused by the existence of R1_R2.
1647 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
1648 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
1649 DCHECK_NE(out_hi, in1_lo);
1650 DCHECK_NE(out_hi, in2_lo);
1651
1652 // input: in1 - 64 bits, in2 - 64 bits
1653 // output: out
1654 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
1655 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
1656 // parts: out.lo = (in1.lo * in2.lo)[31:0]
1657
1658 // IP <- in1.lo * in2.hi
1659 __ mul(IP, in1_lo, in2_hi);
1660 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
1661 __ mla(out_hi, in1_hi, in2_lo, IP);
1662 // out.lo <- (in1.lo * in2.lo)[31:0];
1663 __ umull(out_lo, IP, in1_lo, in2_lo);
1664 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
1665 __ add(out_hi, out_hi, ShifterOperand(IP));
1666 break;
1667 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001668
1669 case Primitive::kPrimFloat: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001670 __ vmuls(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001671 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001672 }
1673
1674 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001675 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1676 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1677 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01001678 break;
1679 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001680
1681 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001682 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001683 }
1684}
1685
Calin Juravle7c4954d2014-10-28 16:57:40 +00001686void LocationsBuilderARM::VisitDiv(HDiv* div) {
1687 LocationSummary* locations =
1688 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1689 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00001690 case Primitive::kPrimInt: {
1691 locations->SetInAt(0, Location::RequiresRegister());
1692 locations->SetInAt(1, Location::RequiresRegister());
1693 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1694 break;
1695 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00001696 case Primitive::kPrimLong: {
1697 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1698 break;
1699 }
1700 case Primitive::kPrimFloat:
1701 case Primitive::kPrimDouble: {
1702 locations->SetInAt(0, Location::RequiresFpuRegister());
1703 locations->SetInAt(1, Location::RequiresFpuRegister());
1704 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1705 break;
1706 }
1707
1708 default:
1709 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1710 }
1711}
1712
1713void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
1714 LocationSummary* locations = div->GetLocations();
1715 Location out = locations->Out();
1716 Location first = locations->InAt(0);
1717 Location second = locations->InAt(1);
1718
1719 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00001720 case Primitive::kPrimInt: {
1721 __ sdiv(out.As<Register>(), first.As<Register>(), second.As<Register>());
1722 break;
1723 }
1724
Calin Juravle7c4954d2014-10-28 16:57:40 +00001725 case Primitive::kPrimLong: {
1726 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1727 break;
1728 }
1729
1730 case Primitive::kPrimFloat: {
1731 __ vdivs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>());
1732 break;
1733 }
1734
1735 case Primitive::kPrimDouble: {
1736 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1737 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1738 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
1739 break;
1740 }
1741
1742 default:
1743 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1744 }
1745}
1746
Calin Juravled0d48522014-11-04 16:40:20 +00001747void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1748 LocationSummary* locations =
1749 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1750 locations->SetInAt(0, Location::RequiresRegister());
1751 if (instruction->HasUses()) {
1752 locations->SetOut(Location::SameAsFirstInput());
1753 }
1754}
1755
1756void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1757 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
1758 codegen_->AddSlowPath(slow_path);
1759
1760 LocationSummary* locations = instruction->GetLocations();
1761 Location value = locations->InAt(0);
1762
1763 DCHECK(value.IsRegister()) << value;
1764 __ cmp(value.As<Register>(), ShifterOperand(0));
1765 __ b(slow_path->GetEntryLabel(), EQ);
1766}
1767
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001768void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001769 LocationSummary* locations =
1770 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001771 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001772 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1773 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1774 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001775}
1776
1777void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
1778 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001779 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001780 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001781 codegen_->InvokeRuntime(
1782 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001783}
1784
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001785void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
1786 LocationSummary* locations =
1787 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1788 InvokeRuntimeCallingConvention calling_convention;
1789 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1790 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1791 locations->SetOut(Location::RegisterLocation(R0));
1792 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1793}
1794
1795void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
1796 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001797 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001798 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001799 codegen_->InvokeRuntime(
1800 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001801}
1802
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001803void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001804 LocationSummary* locations =
1805 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001806 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1807 if (location.IsStackSlot()) {
1808 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1809 } else if (location.IsDoubleStackSlot()) {
1810 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001811 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001812 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001813}
1814
1815void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001816 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001817 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001818}
1819
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001820void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001821 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001822 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001823 locations->SetInAt(0, Location::RequiresRegister());
1824 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001825}
1826
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001827void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
1828 LocationSummary* locations = not_->GetLocations();
1829 Location out = locations->Out();
1830 Location in = locations->InAt(0);
1831 switch (not_->InputAt(0)->GetType()) {
1832 case Primitive::kPrimBoolean:
1833 __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1));
1834 break;
1835
1836 case Primitive::kPrimInt:
1837 __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>()));
1838 break;
1839
1840 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01001841 __ mvn(out.AsRegisterPairLow<Register>(),
1842 ShifterOperand(in.AsRegisterPairLow<Register>()));
1843 __ mvn(out.AsRegisterPairHigh<Register>(),
1844 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001845 break;
1846
1847 default:
1848 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
1849 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001850}
1851
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001852void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001853 LocationSummary* locations =
1854 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001855 locations->SetInAt(0, Location::RequiresRegister());
1856 locations->SetInAt(1, Location::RequiresRegister());
1857 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001858}
1859
1860void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001861 LocationSummary* locations = compare->GetLocations();
1862 switch (compare->InputAt(0)->GetType()) {
1863 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001864 Register output = locations->Out().As<Register>();
1865 Location left = locations->InAt(0);
1866 Location right = locations->InAt(1);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001867 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001868 __ cmp(left.AsRegisterPairHigh<Register>(),
1869 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001870 __ b(&less, LT);
1871 __ b(&greater, GT);
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001872 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
1873 // the status flags.
1874 __ LoadImmediate(output, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001875 __ cmp(left.AsRegisterPairLow<Register>(),
1876 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001877 __ b(&done, EQ);
1878 __ b(&less, CC);
1879
1880 __ Bind(&greater);
1881 __ LoadImmediate(output, 1);
1882 __ b(&done);
1883
1884 __ Bind(&less);
1885 __ LoadImmediate(output, -1);
1886
1887 __ Bind(&done);
1888 break;
1889 }
1890 default:
1891 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1892 }
1893}
1894
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001895void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001896 LocationSummary* locations =
1897 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001898 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1899 locations->SetInAt(i, Location::Any());
1900 }
1901 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001902}
1903
1904void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001905 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001906 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001907}
1908
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001909void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001910 LocationSummary* locations =
1911 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001912 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001913 locations->SetInAt(0, Location::RequiresRegister());
1914 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001915 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001916 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001917 locations->AddTemp(Location::RequiresRegister());
1918 locations->AddTemp(Location::RequiresRegister());
1919 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001920}
1921
1922void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1923 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001924 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001925 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001926 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001927
1928 switch (field_type) {
1929 case Primitive::kPrimBoolean:
1930 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001931 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001932 __ StoreToOffset(kStoreByte, value, obj, offset);
1933 break;
1934 }
1935
1936 case Primitive::kPrimShort:
1937 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001938 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001939 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1940 break;
1941 }
1942
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001943 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001944 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001945 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001946 __ StoreToOffset(kStoreWord, value, obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001947 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001948 Register temp = locations->GetTemp(0).As<Register>();
1949 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001950 codegen_->MarkGCCard(temp, card, obj, value);
1951 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001952 break;
1953 }
1954
1955 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001956 Location value = locations->InAt(1);
1957 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001958 break;
1959 }
1960
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00001961 case Primitive::kPrimFloat: {
1962 SRegister value = locations->InAt(1).As<SRegister>();
1963 __ StoreSToOffset(value, obj, offset);
1964 break;
1965 }
1966
1967 case Primitive::kPrimDouble: {
1968 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>());
1969 __ StoreDToOffset(value, obj, offset);
1970 break;
1971 }
1972
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001973 case Primitive::kPrimVoid:
1974 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001975 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001976 }
1977}
1978
1979void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001980 LocationSummary* locations =
1981 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001982 locations->SetInAt(0, Location::RequiresRegister());
1983 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001984}
1985
1986void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1987 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001988 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001989 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1990
1991 switch (instruction->GetType()) {
1992 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001993 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001994 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1995 break;
1996 }
1997
1998 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001999 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002000 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
2001 break;
2002 }
2003
2004 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002005 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002006 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
2007 break;
2008 }
2009
2010 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002011 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002012 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
2013 break;
2014 }
2015
2016 case Primitive::kPrimInt:
2017 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002018 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002019 __ LoadFromOffset(kLoadWord, out, obj, offset);
2020 break;
2021 }
2022
2023 case Primitive::kPrimLong: {
2024 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002025 Location out = locations->Out();
2026 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002027 break;
2028 }
2029
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002030 case Primitive::kPrimFloat: {
2031 SRegister out = locations->Out().As<SRegister>();
2032 __ LoadSFromOffset(out, obj, offset);
2033 break;
2034 }
2035
2036 case Primitive::kPrimDouble: {
2037 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>());
2038 __ LoadDFromOffset(out, obj, offset);
2039 break;
2040 }
2041
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002042 case Primitive::kPrimVoid:
2043 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002044 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002045 }
2046}
2047
2048void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002049 LocationSummary* locations =
2050 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002051 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002052 if (instruction->HasUses()) {
2053 locations->SetOut(Location::SameAsFirstInput());
2054 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002055}
2056
2057void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002058 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002059 codegen_->AddSlowPath(slow_path);
2060
2061 LocationSummary* locations = instruction->GetLocations();
2062 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002063
2064 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002065 __ cmp(obj.As<Register>(), ShifterOperand(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002066 __ b(slow_path->GetEntryLabel(), EQ);
2067 } else {
2068 DCHECK(obj.IsConstant()) << obj;
2069 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2070 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002071 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002072}
2073
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002074void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002075 LocationSummary* locations =
2076 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002077 locations->SetInAt(0, Location::RequiresRegister());
2078 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2079 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002080}
2081
2082void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
2083 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002084 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002085 Location index = locations->InAt(1);
2086
2087 switch (instruction->GetType()) {
2088 case Primitive::kPrimBoolean: {
2089 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002090 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002091 if (index.IsConstant()) {
2092 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2093 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
2094 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002095 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002096 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
2097 }
2098 break;
2099 }
2100
2101 case Primitive::kPrimByte: {
2102 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002103 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002104 if (index.IsConstant()) {
2105 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2106 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
2107 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002108 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002109 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
2110 }
2111 break;
2112 }
2113
2114 case Primitive::kPrimShort: {
2115 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002116 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002117 if (index.IsConstant()) {
2118 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2119 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
2120 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002121 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002122 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
2123 }
2124 break;
2125 }
2126
2127 case Primitive::kPrimChar: {
2128 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002129 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002130 if (index.IsConstant()) {
2131 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2132 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
2133 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002134 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002135 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
2136 }
2137 break;
2138 }
2139
2140 case Primitive::kPrimInt:
2141 case Primitive::kPrimNot: {
2142 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2143 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002144 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002145 if (index.IsConstant()) {
2146 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2147 __ LoadFromOffset(kLoadWord, out, obj, offset);
2148 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002149 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002150 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
2151 }
2152 break;
2153 }
2154
2155 case Primitive::kPrimLong: {
2156 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002157 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002158 if (index.IsConstant()) {
2159 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002160 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002161 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002162 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
2163 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002164 }
2165 break;
2166 }
2167
2168 case Primitive::kPrimFloat:
2169 case Primitive::kPrimDouble:
2170 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002171 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002172 case Primitive::kPrimVoid:
2173 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002174 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002175 }
2176}
2177
2178void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002179 Primitive::Type value_type = instruction->GetComponentType();
2180 bool is_object = value_type == Primitive::kPrimNot;
2181 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2182 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
2183 if (is_object) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002184 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002185 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2186 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2187 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002188 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002189 locations->SetInAt(0, Location::RequiresRegister());
2190 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2191 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002192 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002193}
2194
2195void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
2196 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002197 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002198 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01002199 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002200
2201 switch (value_type) {
2202 case Primitive::kPrimBoolean:
2203 case Primitive::kPrimByte: {
2204 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002205 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002206 if (index.IsConstant()) {
2207 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2208 __ StoreToOffset(kStoreByte, value, obj, offset);
2209 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002210 __ add(IP, obj, ShifterOperand(index.As<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002211 __ StoreToOffset(kStoreByte, value, IP, data_offset);
2212 }
2213 break;
2214 }
2215
2216 case Primitive::kPrimShort:
2217 case Primitive::kPrimChar: {
2218 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002219 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002220 if (index.IsConstant()) {
2221 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2222 __ StoreToOffset(kStoreHalfword, value, obj, offset);
2223 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002224 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002225 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
2226 }
2227 break;
2228 }
2229
2230 case Primitive::kPrimInt: {
2231 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002232 Register value = locations->InAt(2).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002233 if (index.IsConstant()) {
2234 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2235 __ StoreToOffset(kStoreWord, value, obj, offset);
2236 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002237 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002238 __ StoreToOffset(kStoreWord, value, IP, data_offset);
2239 }
2240 break;
2241 }
2242
2243 case Primitive::kPrimNot: {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002244 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002245 break;
2246 }
2247
2248 case Primitive::kPrimLong: {
2249 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002250 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002251 if (index.IsConstant()) {
2252 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002253 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002254 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002255 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8));
2256 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002257 }
2258 break;
2259 }
2260
2261 case Primitive::kPrimFloat:
2262 case Primitive::kPrimDouble:
2263 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002264 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002265 case Primitive::kPrimVoid:
2266 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07002267 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002268 }
2269}
2270
2271void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002272 LocationSummary* locations =
2273 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002274 locations->SetInAt(0, Location::RequiresRegister());
2275 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002276}
2277
2278void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
2279 LocationSummary* locations = instruction->GetLocations();
2280 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002281 Register obj = locations->InAt(0).As<Register>();
2282 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002283 __ LoadFromOffset(kLoadWord, out, obj, offset);
2284}
2285
2286void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002287 LocationSummary* locations =
2288 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002289 locations->SetInAt(0, Location::RequiresRegister());
2290 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002291 if (instruction->HasUses()) {
2292 locations->SetOut(Location::SameAsFirstInput());
2293 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002294}
2295
2296void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
2297 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002298 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01002299 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002300 codegen_->AddSlowPath(slow_path);
2301
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002302 Register index = locations->InAt(0).As<Register>();
2303 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002304
2305 __ cmp(index, ShifterOperand(length));
2306 __ b(slow_path->GetEntryLabel(), CS);
2307}
2308
2309void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
2310 Label is_null;
2311 __ CompareAndBranchIfZero(value, &is_null);
2312 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
2313 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
2314 __ strb(card, Address(card, temp));
2315 __ Bind(&is_null);
2316}
2317
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002318void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
2319 temp->SetLocations(nullptr);
2320}
2321
2322void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
2323 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002324 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002325}
2326
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002327void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002328 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002329 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002330}
2331
2332void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002333 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2334}
2335
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002336void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
2337 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2338}
2339
2340void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002341 HBasicBlock* block = instruction->GetBlock();
2342 if (block->GetLoopInformation() != nullptr) {
2343 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2344 // The back edge will generate the suspend check.
2345 return;
2346 }
2347 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2348 // The goto will generate the suspend check.
2349 return;
2350 }
2351 GenerateSuspendCheck(instruction, nullptr);
2352}
2353
2354void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
2355 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002356 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002357 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002358 codegen_->AddSlowPath(slow_path);
2359
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002360 __ LoadFromOffset(
2361 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
2362 __ cmp(IP, ShifterOperand(0));
2363 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002364 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002365 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002366 __ Bind(slow_path->GetReturnLabel());
2367 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00002368 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002369 __ b(slow_path->GetEntryLabel());
2370 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002371}
2372
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002373ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
2374 return codegen_->GetAssembler();
2375}
2376
2377void ParallelMoveResolverARM::EmitMove(size_t index) {
2378 MoveOperands* move = moves_.Get(index);
2379 Location source = move->GetSource();
2380 Location destination = move->GetDestination();
2381
2382 if (source.IsRegister()) {
2383 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002384 __ Mov(destination.As<Register>(), source.As<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002385 } else {
2386 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002387 __ StoreToOffset(kStoreWord, source.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002388 SP, destination.GetStackIndex());
2389 }
2390 } else if (source.IsStackSlot()) {
2391 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002392 __ LoadFromOffset(kLoadWord, destination.As<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002393 SP, source.GetStackIndex());
2394 } else {
2395 DCHECK(destination.IsStackSlot());
2396 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2397 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
2398 }
2399 } else {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002400 DCHECK(source.IsConstant());
Roland Levillain476df552014-10-09 17:51:36 +01002401 DCHECK(source.GetConstant()->IsIntConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002402 int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
2403 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002404 __ LoadImmediate(destination.As<Register>(), value);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002405 } else {
2406 DCHECK(destination.IsStackSlot());
2407 __ LoadImmediate(IP, value);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002408 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002409 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002410 }
2411}
2412
2413void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
2414 __ Mov(IP, reg);
2415 __ LoadFromOffset(kLoadWord, reg, SP, mem);
2416 __ StoreToOffset(kStoreWord, IP, SP, mem);
2417}
2418
2419void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
2420 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
2421 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
2422 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
2423 SP, mem1 + stack_offset);
2424 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
2425 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
2426 SP, mem2 + stack_offset);
2427 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
2428}
2429
2430void ParallelMoveResolverARM::EmitSwap(size_t index) {
2431 MoveOperands* move = moves_.Get(index);
2432 Location source = move->GetSource();
2433 Location destination = move->GetDestination();
2434
2435 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002436 DCHECK_NE(source.As<Register>(), IP);
2437 DCHECK_NE(destination.As<Register>(), IP);
2438 __ Mov(IP, source.As<Register>());
2439 __ Mov(source.As<Register>(), destination.As<Register>());
2440 __ Mov(destination.As<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002441 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002442 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002443 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002444 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002445 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
2446 Exchange(source.GetStackIndex(), destination.GetStackIndex());
2447 } else {
2448 LOG(FATAL) << "Unimplemented";
2449 }
2450}
2451
2452void ParallelMoveResolverARM::SpillScratch(int reg) {
2453 __ Push(static_cast<Register>(reg));
2454}
2455
2456void ParallelMoveResolverARM::RestoreScratch(int reg) {
2457 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002458}
2459
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002460void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002461 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
2462 ? LocationSummary::kCallOnSlowPath
2463 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002464 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002465 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002466 locations->SetOut(Location::RequiresRegister());
2467}
2468
2469void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
2470 Register out = cls->GetLocations()->Out().As<Register>();
2471 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002472 DCHECK(!cls->CanCallRuntime());
2473 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002474 codegen_->LoadCurrentMethod(out);
2475 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
2476 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002477 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002478 codegen_->LoadCurrentMethod(out);
2479 __ LoadFromOffset(
2480 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
2481 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002482
2483 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
2484 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
2485 codegen_->AddSlowPath(slow_path);
2486 __ cmp(out, ShifterOperand(0));
2487 __ b(slow_path->GetEntryLabel(), EQ);
2488 if (cls->MustGenerateClinitCheck()) {
2489 GenerateClassInitializationCheck(slow_path, out);
2490 } else {
2491 __ Bind(slow_path->GetExitLabel());
2492 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002493 }
2494}
2495
2496void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
2497 LocationSummary* locations =
2498 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2499 locations->SetInAt(0, Location::RequiresRegister());
2500 if (check->HasUses()) {
2501 locations->SetOut(Location::SameAsFirstInput());
2502 }
2503}
2504
2505void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002506 // We assume the class is not null.
2507 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
2508 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002509 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002510 GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>());
2511}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002512
Nicolas Geoffray424f6762014-11-03 14:51:25 +00002513void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
2514 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002515 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
2516 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
2517 __ b(slow_path->GetEntryLabel(), LT);
2518 // Even if the initialized flag is set, we may be in a situation where caches are not synced
2519 // properly. Therefore, we do a memory fence.
2520 __ dmb(ISH);
2521 __ Bind(slow_path->GetExitLabel());
2522}
2523
2524void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2525 LocationSummary* locations =
2526 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2527 locations->SetInAt(0, Location::RequiresRegister());
2528 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2529}
2530
2531void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2532 LocationSummary* locations = instruction->GetLocations();
2533 Register cls = locations->InAt(0).As<Register>();
2534 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2535
2536 switch (instruction->GetType()) {
2537 case Primitive::kPrimBoolean: {
2538 Register out = locations->Out().As<Register>();
2539 __ LoadFromOffset(kLoadUnsignedByte, out, cls, offset);
2540 break;
2541 }
2542
2543 case Primitive::kPrimByte: {
2544 Register out = locations->Out().As<Register>();
2545 __ LoadFromOffset(kLoadSignedByte, out, cls, offset);
2546 break;
2547 }
2548
2549 case Primitive::kPrimShort: {
2550 Register out = locations->Out().As<Register>();
2551 __ LoadFromOffset(kLoadSignedHalfword, out, cls, offset);
2552 break;
2553 }
2554
2555 case Primitive::kPrimChar: {
2556 Register out = locations->Out().As<Register>();
2557 __ LoadFromOffset(kLoadUnsignedHalfword, out, cls, offset);
2558 break;
2559 }
2560
2561 case Primitive::kPrimInt:
2562 case Primitive::kPrimNot: {
2563 Register out = locations->Out().As<Register>();
2564 __ LoadFromOffset(kLoadWord, out, cls, offset);
2565 break;
2566 }
2567
2568 case Primitive::kPrimLong: {
2569 // TODO: support volatile.
2570 Location out = locations->Out();
2571 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), cls, offset);
2572 break;
2573 }
2574
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002575 case Primitive::kPrimFloat: {
2576 SRegister out = locations->Out().As<SRegister>();
2577 __ LoadSFromOffset(out, cls, offset);
2578 break;
2579 }
2580
2581 case Primitive::kPrimDouble: {
2582 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>());
2583 __ LoadDFromOffset(out, cls, offset);
2584 break;
2585 }
2586
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002587 case Primitive::kPrimVoid:
2588 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2589 UNREACHABLE();
2590 }
2591}
2592
2593void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2594 LocationSummary* locations =
2595 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2596 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
2597 locations->SetInAt(0, Location::RequiresRegister());
2598 locations->SetInAt(1, Location::RequiresRegister());
2599 // Temporary registers for the write barrier.
2600 if (is_object_type) {
2601 locations->AddTemp(Location::RequiresRegister());
2602 locations->AddTemp(Location::RequiresRegister());
2603 }
2604}
2605
2606void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2607 LocationSummary* locations = instruction->GetLocations();
2608 Register cls = locations->InAt(0).As<Register>();
2609 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2610 Primitive::Type field_type = instruction->GetFieldType();
2611
2612 switch (field_type) {
2613 case Primitive::kPrimBoolean:
2614 case Primitive::kPrimByte: {
2615 Register value = locations->InAt(1).As<Register>();
2616 __ StoreToOffset(kStoreByte, value, cls, offset);
2617 break;
2618 }
2619
2620 case Primitive::kPrimShort:
2621 case Primitive::kPrimChar: {
2622 Register value = locations->InAt(1).As<Register>();
2623 __ StoreToOffset(kStoreHalfword, value, cls, offset);
2624 break;
2625 }
2626
2627 case Primitive::kPrimInt:
2628 case Primitive::kPrimNot: {
2629 Register value = locations->InAt(1).As<Register>();
2630 __ StoreToOffset(kStoreWord, value, cls, offset);
2631 if (field_type == Primitive::kPrimNot) {
2632 Register temp = locations->GetTemp(0).As<Register>();
2633 Register card = locations->GetTemp(1).As<Register>();
2634 codegen_->MarkGCCard(temp, card, cls, value);
2635 }
2636 break;
2637 }
2638
2639 case Primitive::kPrimLong: {
2640 Location value = locations->InAt(1);
2641 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), cls, offset);
2642 break;
2643 }
2644
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002645 case Primitive::kPrimFloat: {
2646 SRegister value = locations->InAt(1).As<SRegister>();
2647 __ StoreSToOffset(value, cls, offset);
2648 break;
2649 }
2650
2651 case Primitive::kPrimDouble: {
2652 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>());
2653 __ StoreDToOffset(value, cls, offset);
2654 break;
2655 }
2656
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002657 case Primitive::kPrimVoid:
2658 LOG(FATAL) << "Unreachable type " << field_type;
2659 UNREACHABLE();
2660 }
2661}
2662
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00002663void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
2664 LocationSummary* locations =
2665 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
2666 locations->SetOut(Location::RequiresRegister());
2667}
2668
2669void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
2670 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
2671 codegen_->AddSlowPath(slow_path);
2672
2673 Register out = load->GetLocations()->Out().As<Register>();
2674 codegen_->LoadCurrentMethod(out);
2675 __ LoadFromOffset(
2676 kLoadWord, out, out, mirror::ArtMethod::DexCacheStringsOffset().Int32Value());
2677 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
2678 __ cmp(out, ShifterOperand(0));
2679 __ b(slow_path->GetEntryLabel(), EQ);
2680 __ Bind(slow_path->GetExitLabel());
2681}
2682
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00002683void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
2684 LocationSummary* locations =
2685 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
2686 locations->SetOut(Location::RequiresRegister());
2687}
2688
2689void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
2690 Register out = load->GetLocations()->Out().As<Register>();
2691 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
2692 __ LoadFromOffset(kLoadWord, out, TR, offset);
2693 __ LoadImmediate(IP, 0);
2694 __ StoreToOffset(kStoreWord, IP, TR, offset);
2695}
2696
2697void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
2698 LocationSummary* locations =
2699 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2700 InvokeRuntimeCallingConvention calling_convention;
2701 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2702}
2703
2704void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
2705 codegen_->InvokeRuntime(
2706 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
2707}
2708
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00002709void LocationsBuilderARM::VisitTypeCheck(HTypeCheck* instruction) {
2710 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
2711 ? LocationSummary::kNoCall
2712 : LocationSummary::kCallOnSlowPath;
2713 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
2714 locations->SetInAt(0, Location::RequiresRegister());
2715 locations->SetInAt(1, Location::RequiresRegister());
2716 locations->SetOut(Location::RequiresRegister());
2717}
2718
2719void InstructionCodeGeneratorARM::VisitTypeCheck(HTypeCheck* instruction) {
2720 LocationSummary* locations = instruction->GetLocations();
2721 Register obj = locations->InAt(0).As<Register>();
2722 Register cls = locations->InAt(1).As<Register>();
2723 Register out = locations->Out().As<Register>();
2724 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2725 Label done, zero;
2726 SlowPathCodeARM* slow_path = nullptr;
2727
2728 // Return 0 if `obj` is null.
2729 // TODO: avoid this check if we know obj is not null.
2730 __ cmp(obj, ShifterOperand(0));
2731 __ b(&zero, EQ);
2732 // Compare the class of `obj` with `cls`.
2733 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
2734 __ cmp(out, ShifterOperand(cls));
2735 if (instruction->IsClassFinal()) {
2736 // Classes must be equal for the instanceof to succeed.
2737 __ b(&zero, NE);
2738 __ LoadImmediate(out, 1);
2739 __ b(&done);
2740 } else {
2741 // If the classes are not equal, we go into a slow path.
2742 DCHECK(locations->OnlyCallsOnSlowPath());
2743 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
2744 instruction, Location::RegisterLocation(out));
2745 codegen_->AddSlowPath(slow_path);
2746 __ b(slow_path->GetEntryLabel(), NE);
2747 __ LoadImmediate(out, 1);
2748 __ b(&done);
2749 }
2750 __ Bind(&zero);
2751 __ LoadImmediate(out, 0);
2752 if (slow_path != nullptr) {
2753 __ Bind(slow_path->GetExitLabel());
2754 }
2755 __ Bind(&done);
2756}
2757
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002758} // namespace arm
2759} // namespace art