blob: 0fe28e83522977dbb54623489e7e792267ce8f39 [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
Calin Juravle34166012014-12-19 17:22:29 +000019#include "arch/arm/instruction_set_features_arm.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070020#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010021#include "gc/accounting/card_table.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070022#include "mirror/array-inl.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000023#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010024#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070025#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010026#include "utils/arm/assembler_arm.h"
27#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +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 Geoffray6c2dff82015-01-21 14:56:54 +000040static bool ExpectedPairLayout(Location location) {
41 // We expected this for both core and fpu register pairs.
42 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
43}
44
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010045static constexpr int kCurrentMethodStackOffset = 0;
46
Calin Juravled6fb6cf2014-11-11 19:07:44 +000047static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010048static constexpr size_t kRuntimeParameterCoreRegistersLength =
49 arraysize(kRuntimeParameterCoreRegisters);
Calin Juravled2ec87d2014-12-08 14:24:46 +000050static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
Roland Levillain624279f2014-12-04 11:54:28 +000051static constexpr size_t kRuntimeParameterFpuRegistersLength =
52 arraysize(kRuntimeParameterFpuRegisters);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000053// We unconditionally allocate R5 to ensure we can do long operations
54// with baseline.
55static constexpr Register kCoreSavedRegisterForBaseline = R5;
56static constexpr Register kCoreCalleeSaves[] =
57 { R5, R6, R7, R8, R10, R11, PC };
58static constexpr SRegister kFpuCalleeSaves[] =
59 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010060
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +000061class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010062 public:
63 InvokeRuntimeCallingConvention()
64 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010065 kRuntimeParameterCoreRegistersLength,
66 kRuntimeParameterFpuRegisters,
67 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010068
69 private:
70 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
71};
72
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010074#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010076class SlowPathCodeARM : public SlowPathCode {
77 public:
78 SlowPathCodeARM() : entry_label_(), exit_label_() {}
79
80 Label* GetEntryLabel() { return &entry_label_; }
81 Label* GetExitLabel() { return &exit_label_; }
82
83 private:
84 Label entry_label_;
85 Label exit_label_;
86
87 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
88};
89
90class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010091 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010092 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010093
Alexandre Rames67555f72014-11-18 10:55:16 +000094 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010095 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010096 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010097 arm_codegen->InvokeRuntime(
98 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010099 }
100
101 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100102 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100103 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
104};
105
Calin Juravled0d48522014-11-04 16:40:20 +0000106class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
107 public:
108 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
109
Alexandre Rames67555f72014-11-18 10:55:16 +0000110 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000111 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
112 __ Bind(GetEntryLabel());
113 arm_codegen->InvokeRuntime(
114 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
115 }
116
117 private:
118 HDivZeroCheck* const instruction_;
119 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
120};
121
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100122class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000123 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000124 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100125 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000126
Alexandre Rames67555f72014-11-18 10:55:16 +0000127 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100128 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000129 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100130 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100131 arm_codegen->InvokeRuntime(
132 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100133 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 if (successor_ == nullptr) {
135 __ b(GetReturnLabel());
136 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100137 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100138 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000139 }
140
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100141 Label* GetReturnLabel() {
142 DCHECK(successor_ == nullptr);
143 return &return_label_;
144 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000145
146 private:
147 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100148 // If not null, the block to branch to after the suspend check.
149 HBasicBlock* const successor_;
150
151 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000152 Label return_label_;
153
154 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
155};
156
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100157class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100158 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100159 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
160 Location index_location,
161 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100162 : instruction_(instruction),
163 index_location_(index_location),
164 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100165
Alexandre Rames67555f72014-11-18 10:55:16 +0000166 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100167 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100168 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000169 // We're moving two locations to locations that could overlap, so we need a parallel
170 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000172 codegen->EmitParallelMoves(
173 index_location_,
174 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
175 length_location_,
176 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100177 arm_codegen->InvokeRuntime(
178 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100179 }
180
181 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100182 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183 const Location index_location_;
184 const Location length_location_;
185
186 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
187};
188
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000189class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000191 LoadClassSlowPathARM(HLoadClass* cls,
192 HInstruction* at,
193 uint32_t dex_pc,
194 bool do_clinit)
195 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
196 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
197 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100198
Alexandre Rames67555f72014-11-18 10:55:16 +0000199 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000200 LocationSummary* locations = at_->GetLocations();
201
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100202 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
203 __ Bind(GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204 codegen->SaveLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100205
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100206 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000207 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 int32_t entry_point_offset = do_clinit_
210 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
211 : QUICK_ENTRY_POINT(pInitializeType);
212 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
213
214 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000215 Location out = locations->Out();
216 if (out.IsValid()) {
217 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000218 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
219 }
220 codegen->RestoreLiveRegisters(locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100221 __ b(GetExitLabel());
222 }
223
224 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225 // The class this slow path will load.
226 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100227
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000228 // The instruction where this slow path is happening.
229 // (Might be the load class or an initialization check).
230 HInstruction* const at_;
231
232 // The dex PC of `at_`.
233 const uint32_t dex_pc_;
234
235 // Whether to initialize the class.
236 const bool do_clinit_;
237
238 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100239};
240
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000241class LoadStringSlowPathARM : public SlowPathCodeARM {
242 public:
243 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
244
Alexandre Rames67555f72014-11-18 10:55:16 +0000245 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000246 LocationSummary* locations = instruction_->GetLocations();
247 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
248
249 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
250 __ Bind(GetEntryLabel());
251 codegen->SaveLiveRegisters(locations);
252
253 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800254 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
255 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000256 arm_codegen->InvokeRuntime(
257 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
258 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
259
260 codegen->RestoreLiveRegisters(locations);
261 __ b(GetExitLabel());
262 }
263
264 private:
265 HLoadString* const instruction_;
266
267 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
268};
269
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000270class TypeCheckSlowPathARM : public SlowPathCodeARM {
271 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000272 TypeCheckSlowPathARM(HInstruction* instruction,
273 Location class_to_check,
274 Location object_class,
275 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000277 class_to_check_(class_to_check),
278 object_class_(object_class),
279 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280
Alexandre Rames67555f72014-11-18 10:55:16 +0000281 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000282 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000283 DCHECK(instruction_->IsCheckCast()
284 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285
286 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
287 __ Bind(GetEntryLabel());
288 codegen->SaveLiveRegisters(locations);
289
290 // We're moving two locations to locations that could overlap, so we need a parallel
291 // move resolver.
292 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000293 codegen->EmitParallelMoves(
294 class_to_check_,
295 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
296 object_class_,
297 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000298
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000299 if (instruction_->IsInstanceOf()) {
300 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
301 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
302 } else {
303 DCHECK(instruction_->IsCheckCast());
304 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
305 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000306
307 codegen->RestoreLiveRegisters(locations);
308 __ b(GetExitLabel());
309 }
310
311 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000312 HInstruction* const instruction_;
313 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000314 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000315 uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000316
317 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
318};
319
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000320#undef __
321
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100322#undef __
323#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700324
325inline Condition ARMCondition(IfCondition cond) {
326 switch (cond) {
327 case kCondEQ: return EQ;
328 case kCondNE: return NE;
329 case kCondLT: return LT;
330 case kCondLE: return LE;
331 case kCondGT: return GT;
332 case kCondGE: return GE;
333 default:
334 LOG(FATAL) << "Unknown if condition";
335 }
336 return EQ; // Unreachable.
337}
338
339inline Condition ARMOppositeCondition(IfCondition cond) {
340 switch (cond) {
341 case kCondEQ: return NE;
342 case kCondNE: return EQ;
343 case kCondLT: return GE;
344 case kCondLE: return GT;
345 case kCondGT: return LE;
346 case kCondGE: return LT;
347 default:
348 LOG(FATAL) << "Unknown if condition";
349 }
350 return EQ; // Unreachable.
351}
352
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100353void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
354 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
355}
356
357void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000358 stream << ArmManagedRegister::FromSRegister(SRegister(reg));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100359}
360
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100361size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
362 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
363 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100364}
365
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100366size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
367 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
368 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100369}
370
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000371size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
372 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
373 return kArmWordSize;
374}
375
376size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
377 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
378 return kArmWordSize;
379}
380
Calin Juravle34166012014-12-19 17:22:29 +0000381CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000382 const ArmInstructionSetFeatures& isa_features,
383 const CompilerOptions& compiler_options)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000384 : CodeGenerator(graph,
385 kNumberOfCoreRegisters,
386 kNumberOfSRegisters,
387 kNumberOfRegisterPairs,
388 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
389 arraysize(kCoreCalleeSaves)),
390 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
391 arraysize(kFpuCalleeSaves)),
392 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100393 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100394 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100395 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100396 move_resolver_(graph->GetArena(), this),
Calin Juravle34166012014-12-19 17:22:29 +0000397 assembler_(true),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000398 isa_features_(isa_features) {
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000399 // Save one extra register for baseline. Note that on thumb2, there is no easy
400 // instruction to restore just the PC, so this actually helps both baseline
401 // and non-baseline to save and restore at least two registers at entry and exit.
402 AddAllocatedRegister(Location::RegisterLocation(kCoreSavedRegisterForBaseline));
403 // Save the PC register to mimic Quick.
404 AddAllocatedRegister(Location::RegisterLocation(PC));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100405}
406
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100407Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100408 switch (type) {
409 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100410 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100411 ArmManagedRegister pair =
412 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100413 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
414 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
415
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100416 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
417 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100418 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100419 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100420 }
421
422 case Primitive::kPrimByte:
423 case Primitive::kPrimBoolean:
424 case Primitive::kPrimChar:
425 case Primitive::kPrimShort:
426 case Primitive::kPrimInt:
427 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100428 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100429 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100430 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
431 ArmManagedRegister current =
432 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
433 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100434 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100435 }
436 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100437 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100438 }
439
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000440 case Primitive::kPrimFloat: {
441 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100442 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100443 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100444
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000445 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000446 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
447 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000448 return Location::FpuRegisterPairLocation(reg, reg + 1);
449 }
450
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100451 case Primitive::kPrimVoid:
452 LOG(FATAL) << "Unreachable type " << type;
453 }
454
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100455 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100456}
457
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000458void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100459 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100460 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100461
462 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100463 blocked_core_registers_[SP] = true;
464 blocked_core_registers_[LR] = true;
465 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100466
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100467 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100468 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100469
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100470 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100471 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100472
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000473 if (is_baseline) {
474 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
475 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
476 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000477
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000478 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
479
480 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
481 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
482 }
483 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100484
485 UpdateBlockedPairRegisters();
486}
487
488void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
489 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
490 ArmManagedRegister current =
491 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
492 if (blocked_core_registers_[current.AsRegisterPairLow()]
493 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
494 blocked_register_pairs_[i] = true;
495 }
496 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100497}
498
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100499InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
500 : HGraphVisitor(graph),
501 assembler_(codegen->GetAssembler()),
502 codegen_(codegen) {}
503
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000504static uint32_t LeastSignificantBit(uint32_t mask) {
505 // ffs starts at 1.
506 return ffs(mask) - 1;
507}
508
509void CodeGeneratorARM::ComputeSpillMask() {
510 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
511 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
512 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
513 // We use vpush and vpop for saving and restoring floating point registers, which take
514 // a SRegister and the number of registers to save/restore after that SRegister. We
515 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
516 // but in the range.
517 if (fpu_spill_mask_ != 0) {
518 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
519 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
520 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
521 fpu_spill_mask_ |= (1 << i);
522 }
523 }
524}
525
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000526void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000527 bool skip_overflow_check =
528 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000529 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100530 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000531 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
532 __ LoadFromOffset(kLoadWord, IP, IP, 0);
533 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100534 }
535
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000536 // PC is in the list of callee-save to mimic Quick, but we need to push
537 // LR at entry instead.
538 __ PushList((core_spill_mask_ & (~(1 << PC))) | 1 << LR);
539 if (fpu_spill_mask_ != 0) {
540 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
541 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
542 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000543 __ AddConstant(SP, -(GetFrameSize() - FrameEntrySpillSize()));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100544 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000545}
546
547void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000548 __ AddConstant(SP, GetFrameSize() - FrameEntrySpillSize());
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000549 if (fpu_spill_mask_ != 0) {
550 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
551 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
552 }
553 __ PopList(core_spill_mask_);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000554}
555
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100556void CodeGeneratorARM::Bind(HBasicBlock* block) {
557 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000558}
559
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100560Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
561 switch (load->GetType()) {
562 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100563 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100564 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
565 break;
566
567 case Primitive::kPrimInt:
568 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100569 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100570 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100571
572 case Primitive::kPrimBoolean:
573 case Primitive::kPrimByte:
574 case Primitive::kPrimChar:
575 case Primitive::kPrimShort:
576 case Primitive::kPrimVoid:
577 LOG(FATAL) << "Unexpected type " << load->GetType();
578 }
579
580 LOG(FATAL) << "Unreachable";
581 return Location();
582}
583
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100584Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
585 switch (type) {
586 case Primitive::kPrimBoolean:
587 case Primitive::kPrimByte:
588 case Primitive::kPrimChar:
589 case Primitive::kPrimShort:
590 case Primitive::kPrimInt:
591 case Primitive::kPrimNot: {
592 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000593 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100594 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100595 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100596 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000597 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100598 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100599 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100600
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000601 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100602 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000603 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100604 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000605 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100606 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000607 if (calling_convention.GetRegisterAt(index) == R1) {
608 // Skip R1, and use R2_R3 instead.
609 gp_index_++;
610 index++;
611 }
612 }
613 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
614 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000615 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000616 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000617 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100618 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000619 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
620 }
621 }
622
623 case Primitive::kPrimFloat: {
624 uint32_t stack_index = stack_index_++;
625 if (float_index_ % 2 == 0) {
626 float_index_ = std::max(double_index_, float_index_);
627 }
628 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
629 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
630 } else {
631 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
632 }
633 }
634
635 case Primitive::kPrimDouble: {
636 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
637 uint32_t stack_index = stack_index_;
638 stack_index_ += 2;
639 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
640 uint32_t index = double_index_;
641 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000642 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000643 calling_convention.GetFpuRegisterAt(index),
644 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000645 DCHECK(ExpectedPairLayout(result));
646 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000647 } else {
648 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100649 }
650 }
651
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100652 case Primitive::kPrimVoid:
653 LOG(FATAL) << "Unexpected parameter type " << type;
654 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100655 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100656 return Location();
657}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100658
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000659Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
660 switch (type) {
661 case Primitive::kPrimBoolean:
662 case Primitive::kPrimByte:
663 case Primitive::kPrimChar:
664 case Primitive::kPrimShort:
665 case Primitive::kPrimInt:
666 case Primitive::kPrimNot: {
667 return Location::RegisterLocation(R0);
668 }
669
670 case Primitive::kPrimFloat: {
671 return Location::FpuRegisterLocation(S0);
672 }
673
674 case Primitive::kPrimLong: {
675 return Location::RegisterPairLocation(R0, R1);
676 }
677
678 case Primitive::kPrimDouble: {
679 return Location::FpuRegisterPairLocation(S0, S1);
680 }
681
682 case Primitive::kPrimVoid:
683 return Location();
684 }
685 UNREACHABLE();
686 return Location();
687}
688
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100689void CodeGeneratorARM::Move32(Location destination, Location source) {
690 if (source.Equals(destination)) {
691 return;
692 }
693 if (destination.IsRegister()) {
694 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000695 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100696 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000697 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100698 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000699 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100700 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100701 } else if (destination.IsFpuRegister()) {
702 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000703 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100704 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000705 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100706 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000707 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100708 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100709 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000710 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100711 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000712 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100713 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000714 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100715 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000716 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100717 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
718 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100719 }
720 }
721}
722
723void CodeGeneratorARM::Move64(Location destination, Location source) {
724 if (source.Equals(destination)) {
725 return;
726 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100727 if (destination.IsRegisterPair()) {
728 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000729 EmitParallelMoves(
730 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
731 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
732 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
733 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100734 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000735 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100736 } else {
737 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000738 DCHECK(ExpectedPairLayout(destination));
739 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
740 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000742 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100743 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000744 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
745 SP,
746 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100747 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000748 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100749 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100750 } else {
751 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100752 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000753 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100754 if (source.AsRegisterPairLow<Register>() == R1) {
755 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100756 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
757 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100758 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100759 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100760 SP, destination.GetStackIndex());
761 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000762 } else if (source.IsFpuRegisterPair()) {
763 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
764 SP,
765 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100766 } else {
767 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000768 EmitParallelMoves(
769 Location::StackSlot(source.GetStackIndex()),
770 Location::StackSlot(destination.GetStackIndex()),
771 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
772 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100773 }
774 }
775}
776
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100777void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100778 LocationSummary* locations = instruction->GetLocations();
779 if (locations != nullptr && locations->Out().Equals(location)) {
780 return;
781 }
782
Calin Juravlea21f5982014-11-13 15:53:04 +0000783 if (locations != nullptr && locations->Out().IsConstant()) {
784 HConstant* const_to_move = locations->Out().GetConstant();
785 if (const_to_move->IsIntConstant()) {
786 int32_t value = const_to_move->AsIntConstant()->GetValue();
787 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000788 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000789 } else {
790 DCHECK(location.IsStackSlot());
791 __ LoadImmediate(IP, value);
792 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
793 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000794 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000795 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000796 int64_t value = const_to_move->AsLongConstant()->GetValue();
797 if (location.IsRegisterPair()) {
798 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
799 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
800 } else {
801 DCHECK(location.IsDoubleStackSlot());
802 __ LoadImmediate(IP, Low32Bits(value));
803 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
804 __ LoadImmediate(IP, High32Bits(value));
805 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
806 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100807 }
Roland Levillain476df552014-10-09 17:51:36 +0100808 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
810 switch (instruction->GetType()) {
811 case Primitive::kPrimBoolean:
812 case Primitive::kPrimByte:
813 case Primitive::kPrimChar:
814 case Primitive::kPrimShort:
815 case Primitive::kPrimInt:
816 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100817 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100818 Move32(location, Location::StackSlot(stack_slot));
819 break;
820
821 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100822 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100823 Move64(location, Location::DoubleStackSlot(stack_slot));
824 break;
825
826 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100827 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100828 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000829 } else if (instruction->IsTemporary()) {
830 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000831 if (temp_location.IsStackSlot()) {
832 Move32(location, temp_location);
833 } else {
834 DCHECK(temp_location.IsDoubleStackSlot());
835 Move64(location, temp_location);
836 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000837 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100838 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100839 switch (instruction->GetType()) {
840 case Primitive::kPrimBoolean:
841 case Primitive::kPrimByte:
842 case Primitive::kPrimChar:
843 case Primitive::kPrimShort:
844 case Primitive::kPrimNot:
845 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100846 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100847 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100848 break;
849
850 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100851 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100852 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100853 break;
854
855 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100856 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100857 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000858 }
859}
860
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100861void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
862 HInstruction* instruction,
863 uint32_t dex_pc) {
864 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
865 __ blx(LR);
866 RecordPcInfo(instruction, dex_pc);
867 DCHECK(instruction->IsSuspendCheck()
868 || instruction->IsBoundsCheck()
869 || instruction->IsNullCheck()
Calin Juravled0d48522014-11-04 16:40:20 +0000870 || instruction->IsDivZeroCheck()
Roland Levillain624279f2014-12-04 11:54:28 +0000871 || instruction->GetLocations()->CanCall()
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100872 || !IsLeafMethod());
873}
874
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000875void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000876 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000877}
878
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000879void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000880 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100881 DCHECK(!successor->IsExitBlock());
882
883 HBasicBlock* block = got->GetBlock();
884 HInstruction* previous = got->GetPrevious();
885
886 HLoopInformation* info = block->GetLoopInformation();
887 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
888 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
889 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
890 return;
891 }
892
893 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
894 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
895 }
896 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000897 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000898 }
899}
900
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000901void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000902 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000903}
904
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000905void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700906 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000907 if (kIsDebugBuild) {
908 __ Comment("Unreachable");
909 __ bkpt(0);
910 }
911}
912
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000913void LocationsBuilderARM::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100914 LocationSummary* locations =
915 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100916 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100917 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100918 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100919 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000920}
921
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000922void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700923 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100924 if (cond->IsIntConstant()) {
925 // Constant condition, statically compared against 1.
926 int32_t cond_value = cond->AsIntConstant()->GetValue();
927 if (cond_value == 1) {
928 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
929 if_instr->IfTrueSuccessor())) {
930 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100931 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100932 return;
933 } else {
934 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100935 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100936 } else {
937 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
938 // Condition has been materialized, compare the output to 0
939 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000940 __ cmp(if_instr->GetLocations()->InAt(0).AsRegister<Register>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100941 ShifterOperand(0));
942 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
943 } else {
944 // Condition has not been materialized, use its inputs as the
945 // comparison and its condition as the branch condition.
946 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000947 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000948 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100949 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000950 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100951 } else {
952 DCHECK(locations->InAt(1).IsConstant());
953 int32_t value =
954 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
955 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000956 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
957 __ cmp(left, operand);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100958 } else {
959 Register temp = IP;
960 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000961 __ cmp(left, ShifterOperand(temp));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100962 }
963 }
964 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
965 ARMCondition(cond->AsCondition()->GetCondition()));
966 }
Dave Allison20dfc792014-06-16 20:44:29 -0700967 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100968 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
969 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700970 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000971 }
972}
973
Dave Allison20dfc792014-06-16 20:44:29 -0700974
975void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100976 LocationSummary* locations =
977 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100978 locations->SetInAt(0, Location::RequiresRegister());
979 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100980 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100981 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100982 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000983}
984
Dave Allison20dfc792014-06-16 20:44:29 -0700985void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100986 if (!comp->NeedsMaterialization()) return;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100987 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000988 Register left = locations->InAt(0).AsRegister<Register>();
989
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100990 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000991 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100992 } else {
993 DCHECK(locations->InAt(1).IsConstant());
994 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
995 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000996 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
997 __ cmp(left, operand);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100998 } else {
999 Register temp = IP;
1000 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001001 __ cmp(left, ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001002 }
Dave Allison20dfc792014-06-16 20:44:29 -07001003 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001004 __ it(ARMCondition(comp->GetCondition()), kItElse);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001005 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001006 ARMCondition(comp->GetCondition()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001007 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001008 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -07001009}
1010
1011void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1012 VisitCondition(comp);
1013}
1014
1015void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1016 VisitCondition(comp);
1017}
1018
1019void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1020 VisitCondition(comp);
1021}
1022
1023void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1024 VisitCondition(comp);
1025}
1026
1027void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1028 VisitCondition(comp);
1029}
1030
1031void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1032 VisitCondition(comp);
1033}
1034
1035void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1036 VisitCondition(comp);
1037}
1038
1039void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1040 VisitCondition(comp);
1041}
1042
1043void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1044 VisitCondition(comp);
1045}
1046
1047void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1048 VisitCondition(comp);
1049}
1050
1051void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1052 VisitCondition(comp);
1053}
1054
1055void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1056 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001057}
1058
1059void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001060 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001061}
1062
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001063void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1064 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001065}
1066
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001067void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001068 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001069}
1070
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001071void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001072 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001073 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001074}
1075
1076void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001077 LocationSummary* locations =
1078 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001079 switch (store->InputAt(1)->GetType()) {
1080 case Primitive::kPrimBoolean:
1081 case Primitive::kPrimByte:
1082 case Primitive::kPrimChar:
1083 case Primitive::kPrimShort:
1084 case Primitive::kPrimInt:
1085 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001086 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001087 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1088 break;
1089
1090 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001091 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001092 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1093 break;
1094
1095 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001098}
1099
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001100void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001101 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001102}
1103
1104void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001105 LocationSummary* locations =
1106 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001107 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001108}
1109
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001110void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001111 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001112 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001113}
1114
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001116 LocationSummary* locations =
1117 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001118 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001119}
1120
1121void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1122 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001123 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001124}
1125
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001126void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1127 LocationSummary* locations =
1128 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1129 locations->SetOut(Location::ConstantLocation(constant));
1130}
1131
1132void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1133 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001134 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001135}
1136
1137void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1138 LocationSummary* locations =
1139 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1140 locations->SetOut(Location::ConstantLocation(constant));
1141}
1142
1143void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1144 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001145 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001146}
1147
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001148void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001149 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001150}
1151
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001152void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001153 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001154 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001155}
1156
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001157void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001158 LocationSummary* locations =
1159 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001160 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001161}
1162
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001163void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001164 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001165 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001166}
1167
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001168void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001169 HandleInvoke(invoke);
1170}
1171
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001172void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001173 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001174}
1175
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001176void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001177 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001178
1179 // TODO: Implement all kinds of calls:
1180 // 1) boot -> boot
1181 // 2) app -> boot
1182 // 3) app -> app
1183 //
1184 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1185
1186 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001187 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001188 // temp = temp->dex_cache_resolved_methods_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001189 __ LoadFromOffset(
1190 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
Nicolas Geoffray4e44c822014-12-17 12:25:12 +00001191 // temp = temp[index_in_cache]
1192 __ LoadFromOffset(
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001193 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
Nicolas Geoffray4e44c822014-12-17 12:25:12 +00001194 // LR = temp[offset_of_quick_compiled_code]
1195 __ LoadFromOffset(kLoadWord, LR, temp,
1196 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1197 kArmWordSize).Int32Value());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001198 // LR()
1199 __ blx(LR);
1200
1201 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1202 DCHECK(!codegen_->IsLeafMethod());
1203}
1204
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001205void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001206 LocationSummary* locations =
1207 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001208 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001209
1210 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001211 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001212 HInstruction* input = invoke->InputAt(i);
1213 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1214 }
1215
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001216 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001217}
1218
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001219void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1220 HandleInvoke(invoke);
1221}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001222
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001223void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001224 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001225 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1226 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1227 LocationSummary* locations = invoke->GetLocations();
1228 Location receiver = locations->InAt(0);
1229 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1230 // temp = object->GetClass();
1231 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001232 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1233 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001234 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001235 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001236 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001237 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001238 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001239 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001240 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001241 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001242 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001243 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001244 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001245 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001246 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001247 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001248}
1249
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001250void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1251 HandleInvoke(invoke);
1252 // Add the hidden argument.
1253 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1254}
1255
1256void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1257 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001258 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001259 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1260 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1261 LocationSummary* locations = invoke->GetLocations();
1262 Location receiver = locations->InAt(0);
1263 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1264
1265 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001266 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1267 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001268
1269 // temp = object->GetClass();
1270 if (receiver.IsStackSlot()) {
1271 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1272 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1273 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001274 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001275 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001276 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001277 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001278 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001279 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001280 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1281 // LR = temp->GetEntryPoint();
1282 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1283 // LR();
1284 __ blx(LR);
1285 DCHECK(!codegen_->IsLeafMethod());
1286 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1287}
1288
Roland Levillain88cb1752014-10-20 16:36:47 +01001289void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1290 LocationSummary* locations =
1291 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1292 switch (neg->GetResultType()) {
1293 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001294 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001295 Location::OutputOverlap output_overlaps = (neg->GetResultType() == Primitive::kPrimLong)
1296 ? Location::kOutputOverlap
1297 : Location::kNoOutputOverlap;
Roland Levillain88cb1752014-10-20 16:36:47 +01001298 locations->SetInAt(0, Location::RequiresRegister());
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001299 locations->SetOut(Location::RequiresRegister(), output_overlaps);
Roland Levillain88cb1752014-10-20 16:36:47 +01001300 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001301 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001302
Roland Levillain88cb1752014-10-20 16:36:47 +01001303 case Primitive::kPrimFloat:
1304 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001305 locations->SetInAt(0, Location::RequiresFpuRegister());
1306 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001307 break;
1308
1309 default:
1310 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1311 }
1312}
1313
1314void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1315 LocationSummary* locations = neg->GetLocations();
1316 Location out = locations->Out();
1317 Location in = locations->InAt(0);
1318 switch (neg->GetResultType()) {
1319 case Primitive::kPrimInt:
1320 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001321 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001322 break;
1323
1324 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001325 DCHECK(in.IsRegisterPair());
1326 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1327 __ rsbs(out.AsRegisterPairLow<Register>(),
1328 in.AsRegisterPairLow<Register>(),
1329 ShifterOperand(0));
1330 // We cannot emit an RSC (Reverse Subtract with Carry)
1331 // instruction here, as it does not exist in the Thumb-2
1332 // instruction set. We use the following approach
1333 // using SBC and SUB instead.
1334 //
1335 // out.hi = -C
1336 __ sbc(out.AsRegisterPairHigh<Register>(),
1337 out.AsRegisterPairHigh<Register>(),
1338 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1339 // out.hi = out.hi - in.hi
1340 __ sub(out.AsRegisterPairHigh<Register>(),
1341 out.AsRegisterPairHigh<Register>(),
1342 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1343 break;
1344
Roland Levillain88cb1752014-10-20 16:36:47 +01001345 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001346 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001347 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001348 break;
1349
Roland Levillain88cb1752014-10-20 16:36:47 +01001350 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001351 DCHECK(in.IsFpuRegisterPair());
1352 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1353 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001354 break;
1355
1356 default:
1357 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1358 }
1359}
1360
Roland Levillaindff1f282014-11-05 14:15:05 +00001361void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001362 Primitive::Type result_type = conversion->GetResultType();
1363 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001364 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001365
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001366 // The float-to-long and double-to-long type conversions rely on a
1367 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001368 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001369 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1370 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001371 ? LocationSummary::kCall
1372 : LocationSummary::kNoCall;
1373 LocationSummary* locations =
1374 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1375
Roland Levillaindff1f282014-11-05 14:15:05 +00001376 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001377 case Primitive::kPrimByte:
1378 switch (input_type) {
1379 case Primitive::kPrimShort:
1380 case Primitive::kPrimInt:
1381 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001382 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001383 locations->SetInAt(0, Location::RequiresRegister());
1384 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1385 break;
1386
1387 default:
1388 LOG(FATAL) << "Unexpected type conversion from " << input_type
1389 << " to " << result_type;
1390 }
1391 break;
1392
Roland Levillain01a8d712014-11-14 16:27:39 +00001393 case Primitive::kPrimShort:
1394 switch (input_type) {
1395 case Primitive::kPrimByte:
1396 case Primitive::kPrimInt:
1397 case Primitive::kPrimChar:
1398 // Processing a Dex `int-to-short' instruction.
1399 locations->SetInAt(0, Location::RequiresRegister());
1400 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1401 break;
1402
1403 default:
1404 LOG(FATAL) << "Unexpected type conversion from " << input_type
1405 << " to " << result_type;
1406 }
1407 break;
1408
Roland Levillain946e1432014-11-11 17:35:19 +00001409 case Primitive::kPrimInt:
1410 switch (input_type) {
1411 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001412 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001413 locations->SetInAt(0, Location::Any());
1414 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1415 break;
1416
1417 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001418 // Processing a Dex `float-to-int' instruction.
1419 locations->SetInAt(0, Location::RequiresFpuRegister());
1420 locations->SetOut(Location::RequiresRegister());
1421 locations->AddTemp(Location::RequiresFpuRegister());
1422 break;
1423
Roland Levillain946e1432014-11-11 17:35:19 +00001424 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001425 // Processing a Dex `double-to-int' instruction.
1426 locations->SetInAt(0, Location::RequiresFpuRegister());
1427 locations->SetOut(Location::RequiresRegister());
1428 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001429 break;
1430
1431 default:
1432 LOG(FATAL) << "Unexpected type conversion from " << input_type
1433 << " to " << result_type;
1434 }
1435 break;
1436
Roland Levillaindff1f282014-11-05 14:15:05 +00001437 case Primitive::kPrimLong:
1438 switch (input_type) {
1439 case Primitive::kPrimByte:
1440 case Primitive::kPrimShort:
1441 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001442 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001443 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001444 locations->SetInAt(0, Location::RequiresRegister());
1445 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1446 break;
1447
Roland Levillain624279f2014-12-04 11:54:28 +00001448 case Primitive::kPrimFloat: {
1449 // Processing a Dex `float-to-long' instruction.
1450 InvokeRuntimeCallingConvention calling_convention;
1451 locations->SetInAt(0, Location::FpuRegisterLocation(
1452 calling_convention.GetFpuRegisterAt(0)));
1453 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1454 break;
1455 }
1456
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001457 case Primitive::kPrimDouble: {
1458 // Processing a Dex `double-to-long' instruction.
1459 InvokeRuntimeCallingConvention calling_convention;
1460 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1461 calling_convention.GetFpuRegisterAt(0),
1462 calling_convention.GetFpuRegisterAt(1)));
1463 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001464 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001465 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001466
1467 default:
1468 LOG(FATAL) << "Unexpected type conversion from " << input_type
1469 << " to " << result_type;
1470 }
1471 break;
1472
Roland Levillain981e4542014-11-14 11:47:14 +00001473 case Primitive::kPrimChar:
1474 switch (input_type) {
1475 case Primitive::kPrimByte:
1476 case Primitive::kPrimShort:
1477 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001478 // Processing a Dex `int-to-char' instruction.
1479 locations->SetInAt(0, Location::RequiresRegister());
1480 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1481 break;
1482
1483 default:
1484 LOG(FATAL) << "Unexpected type conversion from " << input_type
1485 << " to " << result_type;
1486 }
1487 break;
1488
Roland Levillaindff1f282014-11-05 14:15:05 +00001489 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001490 switch (input_type) {
1491 case Primitive::kPrimByte:
1492 case Primitive::kPrimShort:
1493 case Primitive::kPrimInt:
1494 case Primitive::kPrimChar:
1495 // Processing a Dex `int-to-float' instruction.
1496 locations->SetInAt(0, Location::RequiresRegister());
1497 locations->SetOut(Location::RequiresFpuRegister());
1498 break;
1499
1500 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001501 // Processing a Dex `long-to-float' instruction.
1502 locations->SetInAt(0, Location::RequiresRegister());
1503 locations->SetOut(Location::RequiresFpuRegister());
1504 locations->AddTemp(Location::RequiresRegister());
1505 locations->AddTemp(Location::RequiresRegister());
1506 locations->AddTemp(Location::RequiresFpuRegister());
1507 locations->AddTemp(Location::RequiresFpuRegister());
1508 break;
1509
Roland Levillaincff13742014-11-17 14:32:17 +00001510 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001511 // Processing a Dex `double-to-float' instruction.
1512 locations->SetInAt(0, Location::RequiresFpuRegister());
1513 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001514 break;
1515
1516 default:
1517 LOG(FATAL) << "Unexpected type conversion from " << input_type
1518 << " to " << result_type;
1519 };
1520 break;
1521
Roland Levillaindff1f282014-11-05 14:15:05 +00001522 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001523 switch (input_type) {
1524 case Primitive::kPrimByte:
1525 case Primitive::kPrimShort:
1526 case Primitive::kPrimInt:
1527 case Primitive::kPrimChar:
1528 // Processing a Dex `int-to-double' instruction.
1529 locations->SetInAt(0, Location::RequiresRegister());
1530 locations->SetOut(Location::RequiresFpuRegister());
1531 break;
1532
1533 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001534 // Processing a Dex `long-to-double' instruction.
1535 locations->SetInAt(0, Location::RequiresRegister());
1536 locations->SetOut(Location::RequiresFpuRegister());
1537 locations->AddTemp(Location::RequiresRegister());
1538 locations->AddTemp(Location::RequiresRegister());
1539 locations->AddTemp(Location::RequiresFpuRegister());
1540 break;
1541
Roland Levillaincff13742014-11-17 14:32:17 +00001542 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001543 // Processing a Dex `float-to-double' instruction.
1544 locations->SetInAt(0, Location::RequiresFpuRegister());
1545 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001546 break;
1547
1548 default:
1549 LOG(FATAL) << "Unexpected type conversion from " << input_type
1550 << " to " << result_type;
1551 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001552 break;
1553
1554 default:
1555 LOG(FATAL) << "Unexpected type conversion from " << input_type
1556 << " to " << result_type;
1557 }
1558}
1559
1560void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1561 LocationSummary* locations = conversion->GetLocations();
1562 Location out = locations->Out();
1563 Location in = locations->InAt(0);
1564 Primitive::Type result_type = conversion->GetResultType();
1565 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001566 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001567 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001568 case Primitive::kPrimByte:
1569 switch (input_type) {
1570 case Primitive::kPrimShort:
1571 case Primitive::kPrimInt:
1572 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001573 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001574 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001575 break;
1576
1577 default:
1578 LOG(FATAL) << "Unexpected type conversion from " << input_type
1579 << " to " << result_type;
1580 }
1581 break;
1582
Roland Levillain01a8d712014-11-14 16:27:39 +00001583 case Primitive::kPrimShort:
1584 switch (input_type) {
1585 case Primitive::kPrimByte:
1586 case Primitive::kPrimInt:
1587 case Primitive::kPrimChar:
1588 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001589 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001590 break;
1591
1592 default:
1593 LOG(FATAL) << "Unexpected type conversion from " << input_type
1594 << " to " << result_type;
1595 }
1596 break;
1597
Roland Levillain946e1432014-11-11 17:35:19 +00001598 case Primitive::kPrimInt:
1599 switch (input_type) {
1600 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001601 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001602 DCHECK(out.IsRegister());
1603 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001604 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001605 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001606 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001607 } else {
1608 DCHECK(in.IsConstant());
1609 DCHECK(in.GetConstant()->IsLongConstant());
1610 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001611 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001612 }
1613 break;
1614
Roland Levillain3f8f9362014-12-02 17:45:01 +00001615 case Primitive::kPrimFloat: {
1616 // Processing a Dex `float-to-int' instruction.
1617 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1618 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1619 __ vcvtis(temp, temp);
1620 __ vmovrs(out.AsRegister<Register>(), temp);
1621 break;
1622 }
1623
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001624 case Primitive::kPrimDouble: {
1625 // Processing a Dex `double-to-int' instruction.
1626 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1627 DRegister temp_d = FromLowSToD(temp_s);
1628 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1629 __ vcvtid(temp_s, temp_d);
1630 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001631 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001632 }
Roland Levillain946e1432014-11-11 17:35:19 +00001633
1634 default:
1635 LOG(FATAL) << "Unexpected type conversion from " << input_type
1636 << " to " << result_type;
1637 }
1638 break;
1639
Roland Levillaindff1f282014-11-05 14:15:05 +00001640 case Primitive::kPrimLong:
1641 switch (input_type) {
1642 case Primitive::kPrimByte:
1643 case Primitive::kPrimShort:
1644 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001645 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001646 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001647 DCHECK(out.IsRegisterPair());
1648 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001649 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001650 // Sign extension.
1651 __ Asr(out.AsRegisterPairHigh<Register>(),
1652 out.AsRegisterPairLow<Register>(),
1653 31);
1654 break;
1655
1656 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001657 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00001658 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1659 conversion,
1660 conversion->GetDexPc());
1661 break;
1662
Roland Levillaindff1f282014-11-05 14:15:05 +00001663 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001664 // Processing a Dex `double-to-long' instruction.
1665 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1666 conversion,
1667 conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001668 break;
1669
1670 default:
1671 LOG(FATAL) << "Unexpected type conversion from " << input_type
1672 << " to " << result_type;
1673 }
1674 break;
1675
Roland Levillain981e4542014-11-14 11:47:14 +00001676 case Primitive::kPrimChar:
1677 switch (input_type) {
1678 case Primitive::kPrimByte:
1679 case Primitive::kPrimShort:
1680 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001681 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001682 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00001683 break;
1684
1685 default:
1686 LOG(FATAL) << "Unexpected type conversion from " << input_type
1687 << " to " << result_type;
1688 }
1689 break;
1690
Roland Levillaindff1f282014-11-05 14:15:05 +00001691 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001692 switch (input_type) {
1693 case Primitive::kPrimByte:
1694 case Primitive::kPrimShort:
1695 case Primitive::kPrimInt:
1696 case Primitive::kPrimChar: {
1697 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001698 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1699 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001700 break;
1701 }
1702
Roland Levillain6d0e4832014-11-27 18:31:21 +00001703 case Primitive::kPrimLong: {
1704 // Processing a Dex `long-to-float' instruction.
1705 Register low = in.AsRegisterPairLow<Register>();
1706 Register high = in.AsRegisterPairHigh<Register>();
1707 SRegister output = out.AsFpuRegister<SRegister>();
1708 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1709 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1710 SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1711 DRegister temp1_d = FromLowSToD(temp1_s);
1712 SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
1713 DRegister temp2_d = FromLowSToD(temp2_s);
1714
1715 // Operations use doubles for precision reasons (each 32-bit
1716 // half of a long fits in the 53-bit mantissa of a double,
1717 // but not in the 24-bit mantissa of a float). This is
1718 // especially important for the low bits. The result is
1719 // eventually converted to float.
1720
1721 // temp1_d = int-to-double(high)
1722 __ vmovsr(temp1_s, high);
1723 __ vcvtdi(temp1_d, temp1_s);
1724 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1725 // as an immediate value into `temp2_d` does not work, as
1726 // this instruction only transfers 8 significant bits of its
1727 // immediate operand. Instead, use two 32-bit core
1728 // registers to load `k2Pow32EncodingForDouble` into
1729 // `temp2_d`.
1730 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1731 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1732 __ vmovdrr(temp2_d, constant_low, constant_high);
1733 // temp1_d = temp1_d * 2^32
1734 __ vmuld(temp1_d, temp1_d, temp2_d);
1735 // temp2_d = unsigned-to-double(low)
1736 __ vmovsr(temp2_s, low);
1737 __ vcvtdu(temp2_d, temp2_s);
1738 // temp1_d = temp1_d + temp2_d
1739 __ vaddd(temp1_d, temp1_d, temp2_d);
1740 // output = double-to-float(temp1_d);
1741 __ vcvtsd(output, temp1_d);
1742 break;
1743 }
1744
Roland Levillaincff13742014-11-17 14:32:17 +00001745 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001746 // Processing a Dex `double-to-float' instruction.
1747 __ vcvtsd(out.AsFpuRegister<SRegister>(),
1748 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00001749 break;
1750
1751 default:
1752 LOG(FATAL) << "Unexpected type conversion from " << input_type
1753 << " to " << result_type;
1754 };
1755 break;
1756
Roland Levillaindff1f282014-11-05 14:15:05 +00001757 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001758 switch (input_type) {
1759 case Primitive::kPrimByte:
1760 case Primitive::kPrimShort:
1761 case Primitive::kPrimInt:
1762 case Primitive::kPrimChar: {
1763 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001764 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001765 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1766 out.AsFpuRegisterPairLow<SRegister>());
1767 break;
1768 }
1769
Roland Levillain647b9ed2014-11-27 12:06:00 +00001770 case Primitive::kPrimLong: {
1771 // Processing a Dex `long-to-double' instruction.
1772 Register low = in.AsRegisterPairLow<Register>();
1773 Register high = in.AsRegisterPairHigh<Register>();
1774 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1775 DRegister out_d = FromLowSToD(out_s);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001776 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1777 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001778 SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1779 DRegister temp_d = FromLowSToD(temp_s);
1780
Roland Levillain647b9ed2014-11-27 12:06:00 +00001781 // out_d = int-to-double(high)
1782 __ vmovsr(out_s, high);
1783 __ vcvtdi(out_d, out_s);
Roland Levillain6d0e4832014-11-27 18:31:21 +00001784 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1785 // as an immediate value into `temp_d` does not work, as
1786 // this instruction only transfers 8 significant bits of its
1787 // immediate operand. Instead, use two 32-bit core
1788 // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
1789 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1790 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001791 __ vmovdrr(temp_d, constant_low, constant_high);
1792 // out_d = out_d * 2^32
1793 __ vmuld(out_d, out_d, temp_d);
1794 // temp_d = unsigned-to-double(low)
1795 __ vmovsr(temp_s, low);
1796 __ vcvtdu(temp_d, temp_s);
1797 // out_d = out_d + temp_d
1798 __ vaddd(out_d, out_d, temp_d);
1799 break;
1800 }
1801
Roland Levillaincff13742014-11-17 14:32:17 +00001802 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001803 // Processing a Dex `float-to-double' instruction.
1804 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1805 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001806 break;
1807
1808 default:
1809 LOG(FATAL) << "Unexpected type conversion from " << input_type
1810 << " to " << result_type;
1811 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001812 break;
1813
1814 default:
1815 LOG(FATAL) << "Unexpected type conversion from " << input_type
1816 << " to " << result_type;
1817 }
1818}
1819
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001820void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001821 LocationSummary* locations =
1822 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001823 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001824 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001825 locations->SetInAt(0, Location::RequiresRegister());
1826 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001827 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1828 break;
1829 }
1830
1831 case Primitive::kPrimLong: {
1832 locations->SetInAt(0, Location::RequiresRegister());
1833 locations->SetInAt(1, Location::RequiresRegister());
1834 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001835 break;
1836 }
1837
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001838 case Primitive::kPrimFloat:
1839 case Primitive::kPrimDouble: {
1840 locations->SetInAt(0, Location::RequiresFpuRegister());
1841 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001842 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001843 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001844 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001845
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001846 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001847 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001848 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001849}
1850
1851void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1852 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001853 Location out = locations->Out();
1854 Location first = locations->InAt(0);
1855 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001856 switch (add->GetResultType()) {
1857 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001858 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001859 __ add(out.AsRegister<Register>(),
1860 first.AsRegister<Register>(),
1861 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001862 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001863 __ AddConstant(out.AsRegister<Register>(),
1864 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001865 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001866 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001867 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001868
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001869 case Primitive::kPrimLong: {
1870 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001871 __ adds(out.AsRegisterPairLow<Register>(),
1872 first.AsRegisterPairLow<Register>(),
1873 ShifterOperand(second.AsRegisterPairLow<Register>()));
1874 __ adc(out.AsRegisterPairHigh<Register>(),
1875 first.AsRegisterPairHigh<Register>(),
1876 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001877 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001878 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001879
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001880 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00001881 __ vadds(out.AsFpuRegister<SRegister>(),
1882 first.AsFpuRegister<SRegister>(),
1883 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001884 break;
1885
1886 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001887 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1888 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1889 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001890 break;
1891
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001892 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001893 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001894 }
1895}
1896
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001897void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001898 LocationSummary* locations =
1899 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001900 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001901 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001902 locations->SetInAt(0, Location::RequiresRegister());
1903 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001904 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1905 break;
1906 }
1907
1908 case Primitive::kPrimLong: {
1909 locations->SetInAt(0, Location::RequiresRegister());
1910 locations->SetInAt(1, Location::RequiresRegister());
1911 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001912 break;
1913 }
Calin Juravle11351682014-10-23 15:38:15 +01001914 case Primitive::kPrimFloat:
1915 case Primitive::kPrimDouble: {
1916 locations->SetInAt(0, Location::RequiresFpuRegister());
1917 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001918 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001919 break;
Calin Juravle11351682014-10-23 15:38:15 +01001920 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001921 default:
Calin Juravle11351682014-10-23 15:38:15 +01001922 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001923 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001924}
1925
1926void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
1927 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01001928 Location out = locations->Out();
1929 Location first = locations->InAt(0);
1930 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001931 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001932 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01001933 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001934 __ sub(out.AsRegister<Register>(),
1935 first.AsRegister<Register>(),
1936 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001937 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001938 __ AddConstant(out.AsRegister<Register>(),
1939 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01001940 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001941 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001942 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001943 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001944
Calin Juravle11351682014-10-23 15:38:15 +01001945 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001946 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01001947 __ subs(out.AsRegisterPairLow<Register>(),
1948 first.AsRegisterPairLow<Register>(),
1949 ShifterOperand(second.AsRegisterPairLow<Register>()));
1950 __ sbc(out.AsRegisterPairHigh<Register>(),
1951 first.AsRegisterPairHigh<Register>(),
1952 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001953 break;
Calin Juravle11351682014-10-23 15:38:15 +01001954 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001955
Calin Juravle11351682014-10-23 15:38:15 +01001956 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00001957 __ vsubs(out.AsFpuRegister<SRegister>(),
1958 first.AsFpuRegister<SRegister>(),
1959 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001960 break;
Calin Juravle11351682014-10-23 15:38:15 +01001961 }
1962
1963 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001964 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1965 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1966 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01001967 break;
1968 }
1969
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001970
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001971 default:
Calin Juravle11351682014-10-23 15:38:15 +01001972 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001973 }
1974}
1975
Calin Juravle34bacdf2014-10-07 20:23:36 +01001976void LocationsBuilderARM::VisitMul(HMul* mul) {
1977 LocationSummary* locations =
1978 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1979 switch (mul->GetResultType()) {
1980 case Primitive::kPrimInt:
1981 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001982 locations->SetInAt(0, Location::RequiresRegister());
1983 locations->SetInAt(1, Location::RequiresRegister());
1984 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001985 break;
1986 }
1987
Calin Juravleb5bfa962014-10-21 18:02:24 +01001988 case Primitive::kPrimFloat:
1989 case Primitive::kPrimDouble: {
1990 locations->SetInAt(0, Location::RequiresFpuRegister());
1991 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001992 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01001993 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001994 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001995
1996 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001997 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001998 }
1999}
2000
2001void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2002 LocationSummary* locations = mul->GetLocations();
2003 Location out = locations->Out();
2004 Location first = locations->InAt(0);
2005 Location second = locations->InAt(1);
2006 switch (mul->GetResultType()) {
2007 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002008 __ mul(out.AsRegister<Register>(),
2009 first.AsRegister<Register>(),
2010 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002011 break;
2012 }
2013 case Primitive::kPrimLong: {
2014 Register out_hi = out.AsRegisterPairHigh<Register>();
2015 Register out_lo = out.AsRegisterPairLow<Register>();
2016 Register in1_hi = first.AsRegisterPairHigh<Register>();
2017 Register in1_lo = first.AsRegisterPairLow<Register>();
2018 Register in2_hi = second.AsRegisterPairHigh<Register>();
2019 Register in2_lo = second.AsRegisterPairLow<Register>();
2020
2021 // Extra checks to protect caused by the existence of R1_R2.
2022 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2023 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2024 DCHECK_NE(out_hi, in1_lo);
2025 DCHECK_NE(out_hi, in2_lo);
2026
2027 // input: in1 - 64 bits, in2 - 64 bits
2028 // output: out
2029 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2030 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2031 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2032
2033 // IP <- in1.lo * in2.hi
2034 __ mul(IP, in1_lo, in2_hi);
2035 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2036 __ mla(out_hi, in1_hi, in2_lo, IP);
2037 // out.lo <- (in1.lo * in2.lo)[31:0];
2038 __ umull(out_lo, IP, in1_lo, in2_lo);
2039 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2040 __ add(out_hi, out_hi, ShifterOperand(IP));
2041 break;
2042 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002043
2044 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002045 __ vmuls(out.AsFpuRegister<SRegister>(),
2046 first.AsFpuRegister<SRegister>(),
2047 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002048 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002049 }
2050
2051 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002052 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2053 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2054 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002055 break;
2056 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002057
2058 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002059 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002060 }
2061}
2062
Calin Juravle7c4954d2014-10-28 16:57:40 +00002063void LocationsBuilderARM::VisitDiv(HDiv* div) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002064 LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong
2065 ? LocationSummary::kCall
2066 : LocationSummary::kNoCall;
2067 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2068
Calin Juravle7c4954d2014-10-28 16:57:40 +00002069 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002070 case Primitive::kPrimInt: {
2071 locations->SetInAt(0, Location::RequiresRegister());
2072 locations->SetInAt(1, Location::RequiresRegister());
2073 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2074 break;
2075 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002076 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002077 InvokeRuntimeCallingConvention calling_convention;
2078 locations->SetInAt(0, Location::RegisterPairLocation(
2079 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2080 locations->SetInAt(1, Location::RegisterPairLocation(
2081 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002082 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002083 break;
2084 }
2085 case Primitive::kPrimFloat:
2086 case Primitive::kPrimDouble: {
2087 locations->SetInAt(0, Location::RequiresFpuRegister());
2088 locations->SetInAt(1, Location::RequiresFpuRegister());
2089 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2090 break;
2091 }
2092
2093 default:
2094 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2095 }
2096}
2097
2098void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2099 LocationSummary* locations = div->GetLocations();
2100 Location out = locations->Out();
2101 Location first = locations->InAt(0);
2102 Location second = locations->InAt(1);
2103
2104 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002105 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002106 __ sdiv(out.AsRegister<Register>(),
2107 first.AsRegister<Register>(),
2108 second.AsRegister<Register>());
Calin Juravled0d48522014-11-04 16:40:20 +00002109 break;
2110 }
2111
Calin Juravle7c4954d2014-10-28 16:57:40 +00002112 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002113 InvokeRuntimeCallingConvention calling_convention;
2114 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2115 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2116 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2117 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2118 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002119 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002120
2121 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002122 break;
2123 }
2124
2125 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002126 __ vdivs(out.AsFpuRegister<SRegister>(),
2127 first.AsFpuRegister<SRegister>(),
2128 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002129 break;
2130 }
2131
2132 case Primitive::kPrimDouble: {
2133 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2134 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2135 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2136 break;
2137 }
2138
2139 default:
2140 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2141 }
2142}
2143
Calin Juravlebacfec32014-11-14 15:54:36 +00002144void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002145 Primitive::Type type = rem->GetResultType();
2146 LocationSummary::CallKind call_kind = type == Primitive::kPrimInt
2147 ? LocationSummary::kNoCall
2148 : LocationSummary::kCall;
Calin Juravlebacfec32014-11-14 15:54:36 +00002149 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2150
Calin Juravled2ec87d2014-12-08 14:24:46 +00002151 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002152 case Primitive::kPrimInt: {
2153 locations->SetInAt(0, Location::RequiresRegister());
2154 locations->SetInAt(1, Location::RequiresRegister());
2155 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2156 locations->AddTemp(Location::RequiresRegister());
2157 break;
2158 }
2159 case Primitive::kPrimLong: {
2160 InvokeRuntimeCallingConvention calling_convention;
2161 locations->SetInAt(0, Location::RegisterPairLocation(
2162 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2163 locations->SetInAt(1, Location::RegisterPairLocation(
2164 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2165 // The runtime helper puts the output in R2,R3.
2166 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2167 break;
2168 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002169 case Primitive::kPrimFloat: {
2170 InvokeRuntimeCallingConvention calling_convention;
2171 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2172 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2173 locations->SetOut(Location::FpuRegisterLocation(S0));
2174 break;
2175 }
2176
Calin Juravlebacfec32014-11-14 15:54:36 +00002177 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002178 InvokeRuntimeCallingConvention calling_convention;
2179 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2180 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2181 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2182 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2183 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002184 break;
2185 }
2186
2187 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002188 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002189 }
2190}
2191
2192void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2193 LocationSummary* locations = rem->GetLocations();
2194 Location out = locations->Out();
2195 Location first = locations->InAt(0);
2196 Location second = locations->InAt(1);
2197
Calin Juravled2ec87d2014-12-08 14:24:46 +00002198 Primitive::Type type = rem->GetResultType();
2199 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002200 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002201 Register reg1 = first.AsRegister<Register>();
2202 Register reg2 = second.AsRegister<Register>();
2203 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002204
2205 // temp = reg1 / reg2 (integer division)
2206 // temp = temp * reg2
2207 // dest = reg1 - temp
2208 __ sdiv(temp, reg1, reg2);
2209 __ mul(temp, temp, reg2);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002210 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
Calin Juravlebacfec32014-11-14 15:54:36 +00002211 break;
2212 }
2213
2214 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002215 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc());
2216 break;
2217 }
2218
Calin Juravled2ec87d2014-12-08 14:24:46 +00002219 case Primitive::kPrimFloat: {
2220 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc());
2221 break;
2222 }
2223
Calin Juravlebacfec32014-11-14 15:54:36 +00002224 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002225 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc());
Calin Juravlebacfec32014-11-14 15:54:36 +00002226 break;
2227 }
2228
2229 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002230 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002231 }
2232}
2233
Calin Juravled0d48522014-11-04 16:40:20 +00002234void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2235 LocationSummary* locations =
2236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002237 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002238 if (instruction->HasUses()) {
2239 locations->SetOut(Location::SameAsFirstInput());
2240 }
2241}
2242
2243void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2244 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2245 codegen_->AddSlowPath(slow_path);
2246
2247 LocationSummary* locations = instruction->GetLocations();
2248 Location value = locations->InAt(0);
2249
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002250 switch (instruction->GetType()) {
2251 case Primitive::kPrimInt: {
2252 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002253 __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002254 __ b(slow_path->GetEntryLabel(), EQ);
2255 } else {
2256 DCHECK(value.IsConstant()) << value;
2257 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2258 __ b(slow_path->GetEntryLabel());
2259 }
2260 }
2261 break;
2262 }
2263 case Primitive::kPrimLong: {
2264 if (value.IsRegisterPair()) {
2265 __ orrs(IP,
2266 value.AsRegisterPairLow<Register>(),
2267 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2268 __ b(slow_path->GetEntryLabel(), EQ);
2269 } else {
2270 DCHECK(value.IsConstant()) << value;
2271 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2272 __ b(slow_path->GetEntryLabel());
2273 }
2274 }
2275 break;
2276 default:
2277 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2278 }
2279 }
Calin Juravled0d48522014-11-04 16:40:20 +00002280}
2281
Calin Juravle9aec02f2014-11-18 23:06:35 +00002282void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2283 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2284
2285 LocationSummary::CallKind call_kind = op->GetResultType() == Primitive::kPrimLong
2286 ? LocationSummary::kCall
2287 : LocationSummary::kNoCall;
2288 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(op, call_kind);
2289
2290 switch (op->GetResultType()) {
2291 case Primitive::kPrimInt: {
2292 locations->SetInAt(0, Location::RequiresRegister());
2293 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
2294 locations->SetOut(Location::RequiresRegister());
2295 break;
2296 }
2297 case Primitive::kPrimLong: {
2298 InvokeRuntimeCallingConvention calling_convention;
2299 locations->SetInAt(0, Location::RegisterPairLocation(
2300 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2301 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002302 // The runtime helper puts the output in R0,R1.
2303 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002304 break;
2305 }
2306 default:
2307 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2308 }
2309}
2310
2311void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2312 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2313
2314 LocationSummary* locations = op->GetLocations();
2315 Location out = locations->Out();
2316 Location first = locations->InAt(0);
2317 Location second = locations->InAt(1);
2318
2319 Primitive::Type type = op->GetResultType();
2320 switch (type) {
2321 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002322 Register out_reg = out.AsRegister<Register>();
2323 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002324 // Arm doesn't mask the shift count so we need to do it ourselves.
2325 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002326 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002327 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2328 if (op->IsShl()) {
2329 __ Lsl(out_reg, first_reg, second_reg);
2330 } else if (op->IsShr()) {
2331 __ Asr(out_reg, first_reg, second_reg);
2332 } else {
2333 __ Lsr(out_reg, first_reg, second_reg);
2334 }
2335 } else {
2336 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2337 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2338 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2339 __ Mov(out_reg, first_reg);
2340 } else if (op->IsShl()) {
2341 __ Lsl(out_reg, first_reg, shift_value);
2342 } else if (op->IsShr()) {
2343 __ Asr(out_reg, first_reg, shift_value);
2344 } else {
2345 __ Lsr(out_reg, first_reg, shift_value);
2346 }
2347 }
2348 break;
2349 }
2350 case Primitive::kPrimLong: {
2351 // TODO: Inline the assembly instead of calling the runtime.
2352 InvokeRuntimeCallingConvention calling_convention;
2353 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2354 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002355 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegister<Register>());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002356 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002357 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002358
2359 int32_t entry_point_offset;
2360 if (op->IsShl()) {
2361 entry_point_offset = QUICK_ENTRY_POINT(pShlLong);
2362 } else if (op->IsShr()) {
2363 entry_point_offset = QUICK_ENTRY_POINT(pShrLong);
2364 } else {
2365 entry_point_offset = QUICK_ENTRY_POINT(pUshrLong);
2366 }
2367 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2368 __ blx(LR);
2369 break;
2370 }
2371 default:
2372 LOG(FATAL) << "Unexpected operation type " << type;
2373 }
2374}
2375
2376void LocationsBuilderARM::VisitShl(HShl* shl) {
2377 HandleShift(shl);
2378}
2379
2380void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2381 HandleShift(shl);
2382}
2383
2384void LocationsBuilderARM::VisitShr(HShr* shr) {
2385 HandleShift(shr);
2386}
2387
2388void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2389 HandleShift(shr);
2390}
2391
2392void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2393 HandleShift(ushr);
2394}
2395
2396void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2397 HandleShift(ushr);
2398}
2399
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002400void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002401 LocationSummary* locations =
2402 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002403 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002404 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2405 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2406 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002407}
2408
2409void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2410 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002411 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002412 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002413 codegen_->InvokeRuntime(
2414 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002415}
2416
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002417void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2418 LocationSummary* locations =
2419 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2420 InvokeRuntimeCallingConvention calling_convention;
2421 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002422 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002423 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002424 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002425}
2426
2427void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2428 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002429 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002430 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002431 codegen_->InvokeRuntime(
2432 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002433}
2434
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002435void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002436 LocationSummary* locations =
2437 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002438 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2439 if (location.IsStackSlot()) {
2440 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2441 } else if (location.IsDoubleStackSlot()) {
2442 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002443 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002444 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002445}
2446
2447void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002448 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002449 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002450}
2451
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002452void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002453 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002454 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002455 locations->SetInAt(0, Location::RequiresRegister());
2456 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002457}
2458
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002459void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2460 LocationSummary* locations = not_->GetLocations();
2461 Location out = locations->Out();
2462 Location in = locations->InAt(0);
2463 switch (not_->InputAt(0)->GetType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002464 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002465 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002466 break;
2467
2468 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002469 __ mvn(out.AsRegisterPairLow<Register>(),
2470 ShifterOperand(in.AsRegisterPairLow<Register>()));
2471 __ mvn(out.AsRegisterPairHigh<Register>(),
2472 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002473 break;
2474
2475 default:
2476 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2477 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002478}
2479
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002480void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002481 LocationSummary* locations =
2482 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002483 switch (compare->InputAt(0)->GetType()) {
2484 case Primitive::kPrimLong: {
2485 locations->SetInAt(0, Location::RequiresRegister());
2486 locations->SetInAt(1, Location::RequiresRegister());
2487 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2488 break;
2489 }
2490 case Primitive::kPrimFloat:
2491 case Primitive::kPrimDouble: {
2492 locations->SetInAt(0, Location::RequiresFpuRegister());
2493 locations->SetInAt(1, Location::RequiresFpuRegister());
2494 locations->SetOut(Location::RequiresRegister());
2495 break;
2496 }
2497 default:
2498 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2499 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002500}
2501
2502void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002503 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002504 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002505 Location left = locations->InAt(0);
2506 Location right = locations->InAt(1);
2507
2508 Label less, greater, done;
2509 Primitive::Type type = compare->InputAt(0)->GetType();
2510 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002511 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002512 __ cmp(left.AsRegisterPairHigh<Register>(),
2513 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002514 __ b(&less, LT);
2515 __ b(&greater, GT);
Calin Juravleddb7df22014-11-25 20:56:51 +00002516 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2517 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002518 __ cmp(left.AsRegisterPairLow<Register>(),
2519 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00002520 break;
2521 }
2522 case Primitive::kPrimFloat:
2523 case Primitive::kPrimDouble: {
2524 __ LoadImmediate(out, 0);
2525 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002526 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002527 } else {
2528 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2529 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2530 }
2531 __ vmstat(); // transfer FP status register to ARM APSR.
2532 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002533 break;
2534 }
2535 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002536 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002537 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002538 __ b(&done, EQ);
2539 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats.
2540
2541 __ Bind(&greater);
2542 __ LoadImmediate(out, 1);
2543 __ b(&done);
2544
2545 __ Bind(&less);
2546 __ LoadImmediate(out, -1);
2547
2548 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002549}
2550
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002551void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002552 LocationSummary* locations =
2553 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002554 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2555 locations->SetInAt(i, Location::Any());
2556 }
2557 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002558}
2559
2560void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002561 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002562 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002563}
2564
Calin Juravle52c48962014-12-16 17:02:57 +00002565void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2566 // TODO (ported from quick): revisit Arm barrier kinds
2567 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings
2568 switch (kind) {
2569 case MemBarrierKind::kAnyStore:
2570 case MemBarrierKind::kLoadAny:
2571 case MemBarrierKind::kAnyAny: {
2572 flavour = DmbOptions::ISH;
2573 break;
2574 }
2575 case MemBarrierKind::kStoreStore: {
2576 flavour = DmbOptions::ISHST;
2577 break;
2578 }
2579 default:
2580 LOG(FATAL) << "Unexpected memory barrier " << kind;
2581 }
2582 __ dmb(flavour);
2583}
2584
2585void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2586 uint32_t offset,
2587 Register out_lo,
2588 Register out_hi) {
2589 if (offset != 0) {
2590 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002591 __ add(IP, addr, ShifterOperand(out_lo));
2592 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002593 }
2594 __ ldrexd(out_lo, out_hi, addr);
2595}
2596
2597void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2598 uint32_t offset,
2599 Register value_lo,
2600 Register value_hi,
2601 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00002602 Register temp2,
2603 HInstruction* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002604 Label fail;
2605 if (offset != 0) {
2606 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002607 __ add(IP, addr, ShifterOperand(temp1));
2608 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002609 }
2610 __ Bind(&fail);
2611 // We need a load followed by store. (The address used in a STREX instruction must
2612 // be the same as the address in the most recently executed LDREX instruction.)
2613 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00002614 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002615 __ strexd(temp1, value_lo, value_hi, addr);
2616 __ cmp(temp1, ShifterOperand(0));
2617 __ b(&fail, NE);
2618}
2619
2620void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2621 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2622
Nicolas Geoffray39468442014-09-02 15:17:15 +01002623 LocationSummary* locations =
2624 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002625 locations->SetInAt(0, Location::RequiresRegister());
2626 locations->SetInAt(1, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002627
Calin Juravle34166012014-12-19 17:22:29 +00002628
Calin Juravle52c48962014-12-16 17:02:57 +00002629 Primitive::Type field_type = field_info.GetFieldType();
2630 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00002631 bool generate_volatile = field_info.IsVolatile()
2632 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002633 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002634 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00002635 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2636 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002637 locations->AddTemp(Location::RequiresRegister());
2638 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002639 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002640 // Arm encoding have some additional constraints for ldrexd/strexd:
2641 // - registers need to be consecutive
2642 // - the first register should be even but not R14.
2643 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2644 // enable Arm encoding.
2645 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2646
2647 locations->AddTemp(Location::RequiresRegister());
2648 locations->AddTemp(Location::RequiresRegister());
2649 if (field_type == Primitive::kPrimDouble) {
2650 // For doubles we need two more registers to copy the value.
2651 locations->AddTemp(Location::RegisterLocation(R2));
2652 locations->AddTemp(Location::RegisterLocation(R3));
2653 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002654 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002655}
2656
Calin Juravle52c48962014-12-16 17:02:57 +00002657void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
2658 const FieldInfo& field_info) {
2659 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2660
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002661 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002662 Register base = locations->InAt(0).AsRegister<Register>();
2663 Location value = locations->InAt(1);
2664
2665 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002666 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002667 Primitive::Type field_type = field_info.GetFieldType();
2668 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2669
2670 if (is_volatile) {
2671 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2672 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002673
2674 switch (field_type) {
2675 case Primitive::kPrimBoolean:
2676 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002677 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002678 break;
2679 }
2680
2681 case Primitive::kPrimShort:
2682 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002683 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002684 break;
2685 }
2686
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002687 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002688 case Primitive::kPrimNot: {
Calin Juravle77520bc2015-01-12 18:45:46 +00002689 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002690 break;
2691 }
2692
2693 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002694 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002695 GenerateWideAtomicStore(base, offset,
2696 value.AsRegisterPairLow<Register>(),
2697 value.AsRegisterPairHigh<Register>(),
2698 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002699 locations->GetTemp(1).AsRegister<Register>(),
2700 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002701 } else {
2702 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002703 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002704 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002705 break;
2706 }
2707
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002708 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002709 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002710 break;
2711 }
2712
2713 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002714 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002715 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002716 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
2717 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
2718
2719 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
2720
2721 GenerateWideAtomicStore(base, offset,
2722 value_reg_lo,
2723 value_reg_hi,
2724 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002725 locations->GetTemp(3).AsRegister<Register>(),
2726 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002727 } else {
2728 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002729 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002730 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002731 break;
2732 }
2733
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002734 case Primitive::kPrimVoid:
2735 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002736 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002737 }
Calin Juravle52c48962014-12-16 17:02:57 +00002738
Calin Juravle77520bc2015-01-12 18:45:46 +00002739 // Longs and doubles are handled in the switch.
2740 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
2741 codegen_->MaybeRecordImplicitNullCheck(instruction);
2742 }
2743
2744 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2745 Register temp = locations->GetTemp(0).AsRegister<Register>();
2746 Register card = locations->GetTemp(1).AsRegister<Register>();
2747 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2748 }
2749
Calin Juravle52c48962014-12-16 17:02:57 +00002750 if (is_volatile) {
2751 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2752 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002753}
2754
Calin Juravle52c48962014-12-16 17:02:57 +00002755void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2756 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002757 LocationSummary* locations =
2758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002759 locations->SetInAt(0, Location::RequiresRegister());
2760 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00002761
Calin Juravle34166012014-12-19 17:22:29 +00002762 bool generate_volatile = field_info.IsVolatile()
2763 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002764 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle34166012014-12-19 17:22:29 +00002765 if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002766 // Arm encoding have some additional constraints for ldrexd/strexd:
2767 // - registers need to be consecutive
2768 // - the first register should be even but not R14.
2769 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2770 // enable Arm encoding.
2771 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2772 locations->AddTemp(Location::RequiresRegister());
2773 locations->AddTemp(Location::RequiresRegister());
2774 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002775}
2776
Calin Juravle52c48962014-12-16 17:02:57 +00002777void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
2778 const FieldInfo& field_info) {
2779 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002780
Calin Juravle52c48962014-12-16 17:02:57 +00002781 LocationSummary* locations = instruction->GetLocations();
2782 Register base = locations->InAt(0).AsRegister<Register>();
2783 Location out = locations->Out();
2784 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002785 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002786 Primitive::Type field_type = field_info.GetFieldType();
2787 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2788
2789 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002790 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002791 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002792 break;
2793 }
2794
2795 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002796 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002797 break;
2798 }
2799
2800 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002801 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002802 break;
2803 }
2804
2805 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002806 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002807 break;
2808 }
2809
2810 case Primitive::kPrimInt:
2811 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002812 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002813 break;
2814 }
2815
2816 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002817 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002818 GenerateWideAtomicLoad(base, offset,
2819 out.AsRegisterPairLow<Register>(),
2820 out.AsRegisterPairHigh<Register>());
2821 } else {
2822 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
2823 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002824 break;
2825 }
2826
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002827 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002828 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002829 break;
2830 }
2831
2832 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002833 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002834 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002835 Register lo = locations->GetTemp(0).AsRegister<Register>();
2836 Register hi = locations->GetTemp(1).AsRegister<Register>();
2837 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00002838 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002839 __ vmovdrr(out_reg, lo, hi);
2840 } else {
2841 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002842 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002843 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002844 break;
2845 }
2846
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002847 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00002848 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002849 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002850 }
Calin Juravle52c48962014-12-16 17:02:57 +00002851
Calin Juravle77520bc2015-01-12 18:45:46 +00002852 // Doubles are handled in the switch.
2853 if (field_type != Primitive::kPrimDouble) {
2854 codegen_->MaybeRecordImplicitNullCheck(instruction);
2855 }
2856
Calin Juravle52c48962014-12-16 17:02:57 +00002857 if (is_volatile) {
2858 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2859 }
2860}
2861
2862void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2863 HandleFieldSet(instruction, instruction->GetFieldInfo());
2864}
2865
2866void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2867 HandleFieldSet(instruction, instruction->GetFieldInfo());
2868}
2869
2870void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
2871 HandleFieldGet(instruction, instruction->GetFieldInfo());
2872}
2873
2874void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
2875 HandleFieldGet(instruction, instruction->GetFieldInfo());
2876}
2877
2878void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2879 HandleFieldGet(instruction, instruction->GetFieldInfo());
2880}
2881
2882void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2883 HandleFieldGet(instruction, instruction->GetFieldInfo());
2884}
2885
2886void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2887 HandleFieldSet(instruction, instruction->GetFieldInfo());
2888}
2889
2890void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2891 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002892}
2893
2894void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002895 LocationSummary* locations =
2896 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00002897 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01002898 if (instruction->HasUses()) {
2899 locations->SetOut(Location::SameAsFirstInput());
2900 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002901}
2902
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002903void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002904 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2905 return;
2906 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002907 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00002908
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002909 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
2910 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2911}
2912
2913void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002914 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002915 codegen_->AddSlowPath(slow_path);
2916
2917 LocationSummary* locations = instruction->GetLocations();
2918 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002919
Calin Juravle77520bc2015-01-12 18:45:46 +00002920 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
2921 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002922}
2923
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002924void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
2925 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2926 GenerateImplicitNullCheck(instruction);
2927 } else {
2928 GenerateExplicitNullCheck(instruction);
2929 }
2930}
2931
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002932void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002933 LocationSummary* locations =
2934 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002935 locations->SetInAt(0, Location::RequiresRegister());
2936 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2937 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002938}
2939
2940void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
2941 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002942 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002943 Location index = locations->InAt(1);
2944
2945 switch (instruction->GetType()) {
2946 case Primitive::kPrimBoolean: {
2947 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002948 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002949 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002950 size_t offset =
2951 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002952 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
2953 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002954 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002955 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
2956 }
2957 break;
2958 }
2959
2960 case Primitive::kPrimByte: {
2961 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002962 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002963 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002964 size_t offset =
2965 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002966 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
2967 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002968 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002969 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
2970 }
2971 break;
2972 }
2973
2974 case Primitive::kPrimShort: {
2975 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002976 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002977 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002978 size_t offset =
2979 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002980 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
2981 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002982 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002983 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
2984 }
2985 break;
2986 }
2987
2988 case Primitive::kPrimChar: {
2989 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002990 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002991 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002992 size_t offset =
2993 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002994 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
2995 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002996 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002997 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
2998 }
2999 break;
3000 }
3001
3002 case Primitive::kPrimInt:
3003 case Primitive::kPrimNot: {
3004 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3005 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003006 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003007 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003008 size_t offset =
3009 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003010 __ LoadFromOffset(kLoadWord, out, obj, offset);
3011 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003012 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003013 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3014 }
3015 break;
3016 }
3017
3018 case Primitive::kPrimLong: {
3019 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003020 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003021 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003022 size_t offset =
3023 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003024 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003025 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003026 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003027 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003028 }
3029 break;
3030 }
3031
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003032 case Primitive::kPrimFloat: {
3033 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3034 Location out = locations->Out();
3035 DCHECK(out.IsFpuRegister());
3036 if (index.IsConstant()) {
3037 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3038 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3039 } else {
3040 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3041 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3042 }
3043 break;
3044 }
3045
3046 case Primitive::kPrimDouble: {
3047 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3048 Location out = locations->Out();
3049 DCHECK(out.IsFpuRegisterPair());
3050 if (index.IsConstant()) {
3051 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3052 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3053 } else {
3054 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3055 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3056 }
3057 break;
3058 }
3059
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003060 case Primitive::kPrimVoid:
3061 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003062 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003063 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003064 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003065}
3066
3067void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003068 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003069
3070 bool needs_write_barrier =
3071 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3072 bool needs_runtime_call = instruction->NeedsTypeCheck();
3073
Nicolas Geoffray39468442014-09-02 15:17:15 +01003074 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003075 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3076 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003077 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003078 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3079 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3080 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003081 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003082 locations->SetInAt(0, Location::RequiresRegister());
3083 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3084 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003085
3086 if (needs_write_barrier) {
3087 // Temporary registers for the write barrier.
3088 locations->AddTemp(Location::RequiresRegister());
3089 locations->AddTemp(Location::RequiresRegister());
3090 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003091 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003092}
3093
3094void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3095 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003096 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003097 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003098 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003099 bool needs_runtime_call = locations->WillCall();
3100 bool needs_write_barrier =
3101 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003102
3103 switch (value_type) {
3104 case Primitive::kPrimBoolean:
3105 case Primitive::kPrimByte: {
3106 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003107 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003108 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003109 size_t offset =
3110 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003111 __ StoreToOffset(kStoreByte, value, obj, offset);
3112 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003113 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003114 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3115 }
3116 break;
3117 }
3118
3119 case Primitive::kPrimShort:
3120 case Primitive::kPrimChar: {
3121 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003122 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003123 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003124 size_t offset =
3125 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003126 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3127 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003128 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003129 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3130 }
3131 break;
3132 }
3133
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003134 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003135 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003136 if (!needs_runtime_call) {
3137 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003139 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003140 size_t offset =
3141 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003142 __ StoreToOffset(kStoreWord, value, obj, offset);
3143 } else {
3144 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003145 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003146 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3147 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003148 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003149 if (needs_write_barrier) {
3150 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003151 Register temp = locations->GetTemp(0).AsRegister<Register>();
3152 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003153 codegen_->MarkGCCard(temp, card, obj, value);
3154 }
3155 } else {
3156 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003157 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3158 instruction,
3159 instruction->GetDexPc());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003160 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003161 break;
3162 }
3163
3164 case Primitive::kPrimLong: {
3165 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003166 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003167 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003168 size_t offset =
3169 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003170 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003171 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003172 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003173 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003174 }
3175 break;
3176 }
3177
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003178 case Primitive::kPrimFloat: {
3179 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3180 Location value = locations->InAt(2);
3181 DCHECK(value.IsFpuRegister());
3182 if (index.IsConstant()) {
3183 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3184 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3185 } else {
3186 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3187 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3188 }
3189 break;
3190 }
3191
3192 case Primitive::kPrimDouble: {
3193 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3194 Location value = locations->InAt(2);
3195 DCHECK(value.IsFpuRegisterPair());
3196 if (index.IsConstant()) {
3197 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3198 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3199 } else {
3200 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3201 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3202 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003203
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003204 break;
3205 }
3206
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003207 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003208 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003209 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003210 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003211
3212 // Ints and objects are handled in the switch.
3213 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3214 codegen_->MaybeRecordImplicitNullCheck(instruction);
3215 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003216}
3217
3218void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003219 LocationSummary* locations =
3220 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003221 locations->SetInAt(0, Location::RequiresRegister());
3222 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003223}
3224
3225void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3226 LocationSummary* locations = instruction->GetLocations();
3227 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003228 Register obj = locations->InAt(0).AsRegister<Register>();
3229 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003230 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003231 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003232}
3233
3234void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003235 LocationSummary* locations =
3236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003237 locations->SetInAt(0, Location::RequiresRegister());
3238 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003239 if (instruction->HasUses()) {
3240 locations->SetOut(Location::SameAsFirstInput());
3241 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003242}
3243
3244void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3245 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003246 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003247 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003248 codegen_->AddSlowPath(slow_path);
3249
Roland Levillain271ab9c2014-11-27 15:23:57 +00003250 Register index = locations->InAt(0).AsRegister<Register>();
3251 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003252
3253 __ cmp(index, ShifterOperand(length));
3254 __ b(slow_path->GetEntryLabel(), CS);
3255}
3256
3257void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
3258 Label is_null;
3259 __ CompareAndBranchIfZero(value, &is_null);
3260 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3261 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3262 __ strb(card, Address(card, temp));
3263 __ Bind(&is_null);
3264}
3265
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003266void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3267 temp->SetLocations(nullptr);
3268}
3269
3270void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3271 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003272 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003273}
3274
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003275void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003276 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003277 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003278}
3279
3280void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003281 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3282}
3283
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003284void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3285 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3286}
3287
3288void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003289 HBasicBlock* block = instruction->GetBlock();
3290 if (block->GetLoopInformation() != nullptr) {
3291 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3292 // The back edge will generate the suspend check.
3293 return;
3294 }
3295 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3296 // The goto will generate the suspend check.
3297 return;
3298 }
3299 GenerateSuspendCheck(instruction, nullptr);
3300}
3301
3302void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3303 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003304 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003305 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003306 codegen_->AddSlowPath(slow_path);
3307
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003308 __ LoadFromOffset(
3309 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3310 __ cmp(IP, ShifterOperand(0));
3311 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003312 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003313 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003314 __ Bind(slow_path->GetReturnLabel());
3315 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003316 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003317 __ b(slow_path->GetEntryLabel());
3318 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003319}
3320
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003321ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3322 return codegen_->GetAssembler();
3323}
3324
3325void ParallelMoveResolverARM::EmitMove(size_t index) {
3326 MoveOperands* move = moves_.Get(index);
3327 Location source = move->GetSource();
3328 Location destination = move->GetDestination();
3329
3330 if (source.IsRegister()) {
3331 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003332 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003333 } else {
3334 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003335 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003336 SP, destination.GetStackIndex());
3337 }
3338 } else if (source.IsStackSlot()) {
3339 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003340 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003341 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003342 } else if (destination.IsFpuRegister()) {
3343 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003344 } else {
3345 DCHECK(destination.IsStackSlot());
3346 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3347 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3348 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003349 } else if (source.IsFpuRegister()) {
3350 if (destination.IsFpuRegister()) {
3351 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003352 } else {
3353 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003354 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3355 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003356 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003357 DCHECK(destination.IsDoubleStackSlot()) << destination;
3358 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3359 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3360 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
3361 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003362 } else {
3363 DCHECK(source.IsConstant()) << source;
3364 HInstruction* constant = source.GetConstant();
3365 if (constant->IsIntConstant()) {
3366 int32_t value = constant->AsIntConstant()->GetValue();
3367 if (destination.IsRegister()) {
3368 __ LoadImmediate(destination.AsRegister<Register>(), value);
3369 } else {
3370 DCHECK(destination.IsStackSlot());
3371 __ LoadImmediate(IP, value);
3372 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3373 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003374 } else if (constant->IsLongConstant()) {
3375 int64_t value = constant->AsLongConstant()->GetValue();
3376 if (destination.IsRegister()) {
3377 // In the presence of long or double constants, the parallel move resolver will
3378 // split the move into two, but keeps the same constant for both moves. Here,
3379 // we use the low or high part depending on which register this move goes to.
3380 if (destination.reg() % 2 == 0) {
3381 __ LoadImmediate(destination.AsRegister<Register>(), Low32Bits(value));
3382 } else {
3383 __ LoadImmediate(destination.AsRegister<Register>(), High32Bits(value));
3384 }
3385 } else {
3386 DCHECK(destination.IsDoubleStackSlot());
3387 __ LoadImmediate(IP, Low32Bits(value));
3388 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3389 __ LoadImmediate(IP, High32Bits(value));
3390 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3391 }
3392 } else if (constant->IsDoubleConstant()) {
3393 double value = constant->AsDoubleConstant()->GetValue();
3394 uint64_t int_value = bit_cast<uint64_t, double>(value);
3395 if (destination.IsFpuRegister()) {
3396 // In the presence of long or double constants, the parallel move resolver will
3397 // split the move into two, but keeps the same constant for both moves. Here,
3398 // we use the low or high part depending on which register this move goes to.
3399 if (destination.reg() % 2 == 0) {
3400 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
3401 bit_cast<float, uint32_t>(Low32Bits(int_value)));
3402 } else {
3403 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
3404 bit_cast<float, uint32_t>(High32Bits(int_value)));
3405 }
3406 } else {
3407 DCHECK(destination.IsDoubleStackSlot());
3408 __ LoadImmediate(IP, Low32Bits(int_value));
3409 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3410 __ LoadImmediate(IP, High32Bits(int_value));
3411 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3412 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003413 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003414 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003415 float value = constant->AsFloatConstant()->GetValue();
3416 if (destination.IsFpuRegister()) {
3417 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3418 } else {
3419 DCHECK(destination.IsStackSlot());
3420 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3421 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3422 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003423 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003424 }
3425}
3426
3427void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3428 __ Mov(IP, reg);
3429 __ LoadFromOffset(kLoadWord, reg, SP, mem);
3430 __ StoreToOffset(kStoreWord, IP, SP, mem);
3431}
3432
3433void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3434 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3435 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3436 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3437 SP, mem1 + stack_offset);
3438 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3439 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3440 SP, mem2 + stack_offset);
3441 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3442}
3443
3444void ParallelMoveResolverARM::EmitSwap(size_t index) {
3445 MoveOperands* move = moves_.Get(index);
3446 Location source = move->GetSource();
3447 Location destination = move->GetDestination();
3448
3449 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003450 DCHECK_NE(source.AsRegister<Register>(), IP);
3451 DCHECK_NE(destination.AsRegister<Register>(), IP);
3452 __ Mov(IP, source.AsRegister<Register>());
3453 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3454 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003455 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003456 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003457 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003458 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003459 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3460 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003461 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003462 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003463 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003464 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003465 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3466 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3467 : destination.AsFpuRegister<SRegister>();
3468 int mem = source.IsFpuRegister()
3469 ? destination.GetStackIndex()
3470 : source.GetStackIndex();
3471
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003472 __ vmovrs(IP, reg);
3473 __ LoadFromOffset(kLoadWord, IP, SP, mem);
3474 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003475 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003476 Exchange(source.GetStackIndex(), destination.GetStackIndex());
3477 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003478 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003479 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003480 }
3481}
3482
3483void ParallelMoveResolverARM::SpillScratch(int reg) {
3484 __ Push(static_cast<Register>(reg));
3485}
3486
3487void ParallelMoveResolverARM::RestoreScratch(int reg) {
3488 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003489}
3490
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003491void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003492 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3493 ? LocationSummary::kCallOnSlowPath
3494 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003495 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003496 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003497 locations->SetOut(Location::RequiresRegister());
3498}
3499
3500void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003501 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003502 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003503 DCHECK(!cls->CanCallRuntime());
3504 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003505 codegen_->LoadCurrentMethod(out);
3506 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3507 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003508 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003509 codegen_->LoadCurrentMethod(out);
3510 __ LoadFromOffset(
3511 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
3512 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003513
3514 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3515 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3516 codegen_->AddSlowPath(slow_path);
3517 __ cmp(out, ShifterOperand(0));
3518 __ b(slow_path->GetEntryLabel(), EQ);
3519 if (cls->MustGenerateClinitCheck()) {
3520 GenerateClassInitializationCheck(slow_path, out);
3521 } else {
3522 __ Bind(slow_path->GetExitLabel());
3523 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003524 }
3525}
3526
3527void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3528 LocationSummary* locations =
3529 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3530 locations->SetInAt(0, Location::RequiresRegister());
3531 if (check->HasUses()) {
3532 locations->SetOut(Location::SameAsFirstInput());
3533 }
3534}
3535
3536void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003537 // We assume the class is not null.
3538 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3539 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003540 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003541 GenerateClassInitializationCheck(slow_path,
3542 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003543}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003544
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003545void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3546 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003547 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3548 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3549 __ b(slow_path->GetEntryLabel(), LT);
3550 // Even if the initialized flag is set, we may be in a situation where caches are not synced
3551 // properly. Therefore, we do a memory fence.
3552 __ dmb(ISH);
3553 __ Bind(slow_path->GetExitLabel());
3554}
3555
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003556void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3557 LocationSummary* locations =
3558 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3559 locations->SetOut(Location::RequiresRegister());
3560}
3561
3562void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
3563 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
3564 codegen_->AddSlowPath(slow_path);
3565
Roland Levillain271ab9c2014-11-27 15:23:57 +00003566 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003567 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003568 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3569 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003570 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
3571 __ cmp(out, ShifterOperand(0));
3572 __ b(slow_path->GetEntryLabel(), EQ);
3573 __ Bind(slow_path->GetExitLabel());
3574}
3575
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003576void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
3577 LocationSummary* locations =
3578 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3579 locations->SetOut(Location::RequiresRegister());
3580}
3581
3582void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003583 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003584 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
3585 __ LoadFromOffset(kLoadWord, out, TR, offset);
3586 __ LoadImmediate(IP, 0);
3587 __ StoreToOffset(kStoreWord, IP, TR, offset);
3588}
3589
3590void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
3591 LocationSummary* locations =
3592 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3593 InvokeRuntimeCallingConvention calling_convention;
3594 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3595}
3596
3597void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
3598 codegen_->InvokeRuntime(
3599 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
3600}
3601
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003602void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003603 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3604 ? LocationSummary::kNoCall
3605 : LocationSummary::kCallOnSlowPath;
3606 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3607 locations->SetInAt(0, Location::RequiresRegister());
3608 locations->SetInAt(1, Location::RequiresRegister());
3609 locations->SetOut(Location::RequiresRegister());
3610}
3611
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003612void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003613 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003614 Register obj = locations->InAt(0).AsRegister<Register>();
3615 Register cls = locations->InAt(1).AsRegister<Register>();
3616 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003617 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3618 Label done, zero;
3619 SlowPathCodeARM* slow_path = nullptr;
3620
3621 // Return 0 if `obj` is null.
3622 // TODO: avoid this check if we know obj is not null.
3623 __ cmp(obj, ShifterOperand(0));
3624 __ b(&zero, EQ);
3625 // Compare the class of `obj` with `cls`.
3626 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
3627 __ cmp(out, ShifterOperand(cls));
3628 if (instruction->IsClassFinal()) {
3629 // Classes must be equal for the instanceof to succeed.
3630 __ b(&zero, NE);
3631 __ LoadImmediate(out, 1);
3632 __ b(&done);
3633 } else {
3634 // If the classes are not equal, we go into a slow path.
3635 DCHECK(locations->OnlyCallsOnSlowPath());
3636 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003637 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003638 codegen_->AddSlowPath(slow_path);
3639 __ b(slow_path->GetEntryLabel(), NE);
3640 __ LoadImmediate(out, 1);
3641 __ b(&done);
3642 }
3643 __ Bind(&zero);
3644 __ LoadImmediate(out, 0);
3645 if (slow_path != nullptr) {
3646 __ Bind(slow_path->GetExitLabel());
3647 }
3648 __ Bind(&done);
3649}
3650
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003651void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
3652 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3653 instruction, LocationSummary::kCallOnSlowPath);
3654 locations->SetInAt(0, Location::RequiresRegister());
3655 locations->SetInAt(1, Location::RequiresRegister());
3656 locations->AddTemp(Location::RequiresRegister());
3657}
3658
3659void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
3660 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 Register obj = locations->InAt(0).AsRegister<Register>();
3662 Register cls = locations->InAt(1).AsRegister<Register>();
3663 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003664 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3665
3666 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3667 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3668 codegen_->AddSlowPath(slow_path);
3669
3670 // TODO: avoid this check if we know obj is not null.
3671 __ cmp(obj, ShifterOperand(0));
3672 __ b(slow_path->GetExitLabel(), EQ);
3673 // Compare the class of `obj` with `cls`.
3674 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
3675 __ cmp(temp, ShifterOperand(cls));
3676 __ b(slow_path->GetEntryLabel(), NE);
3677 __ Bind(slow_path->GetExitLabel());
3678}
3679
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003680void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3681 LocationSummary* locations =
3682 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3683 InvokeRuntimeCallingConvention calling_convention;
3684 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3685}
3686
3687void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3688 codegen_->InvokeRuntime(instruction->IsEnter()
3689 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
3690 instruction,
3691 instruction->GetDexPc());
3692}
3693
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003694void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3695void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3696void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3697
3698void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3699 LocationSummary* locations =
3700 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3701 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3702 || instruction->GetResultType() == Primitive::kPrimLong);
3703 locations->SetInAt(0, Location::RequiresRegister());
3704 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003705 Location::OutputOverlap output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong)
3706 ? Location::kOutputOverlap
3707 : Location::kNoOutputOverlap;
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003708 locations->SetOut(Location::RequiresRegister(), output_overlaps);
3709}
3710
3711void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
3712 HandleBitwiseOperation(instruction);
3713}
3714
3715void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
3716 HandleBitwiseOperation(instruction);
3717}
3718
3719void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
3720 HandleBitwiseOperation(instruction);
3721}
3722
3723void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3724 LocationSummary* locations = instruction->GetLocations();
3725
3726 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003727 Register first = locations->InAt(0).AsRegister<Register>();
3728 Register second = locations->InAt(1).AsRegister<Register>();
3729 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003730 if (instruction->IsAnd()) {
3731 __ and_(out, first, ShifterOperand(second));
3732 } else if (instruction->IsOr()) {
3733 __ orr(out, first, ShifterOperand(second));
3734 } else {
3735 DCHECK(instruction->IsXor());
3736 __ eor(out, first, ShifterOperand(second));
3737 }
3738 } else {
3739 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3740 Location first = locations->InAt(0);
3741 Location second = locations->InAt(1);
3742 Location out = locations->Out();
3743 if (instruction->IsAnd()) {
3744 __ and_(out.AsRegisterPairLow<Register>(),
3745 first.AsRegisterPairLow<Register>(),
3746 ShifterOperand(second.AsRegisterPairLow<Register>()));
3747 __ and_(out.AsRegisterPairHigh<Register>(),
3748 first.AsRegisterPairHigh<Register>(),
3749 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3750 } else if (instruction->IsOr()) {
3751 __ orr(out.AsRegisterPairLow<Register>(),
3752 first.AsRegisterPairLow<Register>(),
3753 ShifterOperand(second.AsRegisterPairLow<Register>()));
3754 __ orr(out.AsRegisterPairHigh<Register>(),
3755 first.AsRegisterPairHigh<Register>(),
3756 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3757 } else {
3758 DCHECK(instruction->IsXor());
3759 __ eor(out.AsRegisterPairLow<Register>(),
3760 first.AsRegisterPairLow<Register>(),
3761 ShifterOperand(second.AsRegisterPairLow<Register>()));
3762 __ eor(out.AsRegisterPairHigh<Register>(),
3763 first.AsRegisterPairHigh<Register>(),
3764 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3765 }
3766 }
3767}
3768
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003769} // namespace arm
3770} // namespace art