blob: cfc798a34e2e9f068545705c39ca8d9bdd56d006 [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"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080022#include "intrinsics.h"
23#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070024#include "mirror/array-inl.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000025#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010026#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070027#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "utils/arm/assembler_arm.h"
29#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000030#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010031#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000032
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace arm {
36
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000037static bool ExpectedPairLayout(Location location) {
38 // We expected this for both core and fpu register pairs.
39 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
40}
41
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010042static constexpr int kCurrentMethodStackOffset = 0;
43
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000044// We unconditionally allocate R5 to ensure we can do long operations
45// with baseline.
46static constexpr Register kCoreSavedRegisterForBaseline = R5;
47static constexpr Register kCoreCalleeSaves[] =
48 { R5, R6, R7, R8, R10, R11, PC };
49static constexpr SRegister kFpuCalleeSaves[] =
50 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010051
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000052// D31 cannot be split into two S registers, and the register allocator only works on
53// S registers. Therefore there is no need to block it.
54static constexpr DRegister DTMP = D31;
55
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010057#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010058
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010059class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010061 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010062
Alexandre Rames67555f72014-11-18 10:55:16 +000063 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010064 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010066 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000067 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 }
69
70 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
73};
74
Calin Juravled0d48522014-11-04 16:40:20 +000075class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
76 public:
77 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
78
Alexandre Rames67555f72014-11-18 10:55:16 +000079 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000080 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
81 __ Bind(GetEntryLabel());
82 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000083 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +000084 }
85
86 private:
87 HDivZeroCheck* const instruction_;
88 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
89};
90
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010091class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000092 public:
Alexandre Rames67555f72014-11-18 10:55:16 +000093 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +010094 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000095
Alexandre Rames67555f72014-11-18 10:55:16 +000096 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010097 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000098 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000099 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100100 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000101 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000102 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100103 if (successor_ == nullptr) {
104 __ b(GetReturnLabel());
105 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100106 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100107 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000108 }
109
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100110 Label* GetReturnLabel() {
111 DCHECK(successor_ == nullptr);
112 return &return_label_;
113 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000114
115 private:
116 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100117 // If not null, the block to branch to after the suspend check.
118 HBasicBlock* const successor_;
119
120 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 Label return_label_;
122
123 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
124};
125
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100126class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100128 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
129 Location index_location,
130 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100131 : instruction_(instruction),
132 index_location_(index_location),
133 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100134
Alexandre Rames67555f72014-11-18 10:55:16 +0000135 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100136 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100137 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000138 // We're moving two locations to locations that could overlap, so we need a parallel
139 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000141 codegen->EmitParallelMoves(
142 index_location_,
143 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
144 length_location_,
145 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100146 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000147 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100148 }
149
150 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 const Location index_location_;
153 const Location length_location_;
154
155 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
156};
157
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000158class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100159 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000160 LoadClassSlowPathARM(HLoadClass* cls,
161 HInstruction* at,
162 uint32_t dex_pc,
163 bool do_clinit)
164 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
165 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
166 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100167
Alexandre Rames67555f72014-11-18 10:55:16 +0000168 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000169 LocationSummary* locations = at_->GetLocations();
170
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100171 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
172 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000173 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100174
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100175 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000176 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100177 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000178 int32_t entry_point_offset = do_clinit_
179 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
180 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000181 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000182
183 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000184 Location out = locations->Out();
185 if (out.IsValid()) {
186 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000187 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
188 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000189 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 __ b(GetExitLabel());
191 }
192
193 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000194 // The class this slow path will load.
195 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 // The instruction where this slow path is happening.
198 // (Might be the load class or an initialization check).
199 HInstruction* const at_;
200
201 // The dex PC of `at_`.
202 const uint32_t dex_pc_;
203
204 // Whether to initialize the class.
205 const bool do_clinit_;
206
207 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208};
209
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000210class LoadStringSlowPathARM : public SlowPathCodeARM {
211 public:
212 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
213
Alexandre Rames67555f72014-11-18 10:55:16 +0000214 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000215 LocationSummary* locations = instruction_->GetLocations();
216 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
217
218 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
219 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000220 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000221
222 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800223 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
224 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000225 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000226 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000227 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
228
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000229 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000230 __ b(GetExitLabel());
231 }
232
233 private:
234 HLoadString* const instruction_;
235
236 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
237};
238
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000239class TypeCheckSlowPathARM : public SlowPathCodeARM {
240 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000241 TypeCheckSlowPathARM(HInstruction* instruction,
242 Location class_to_check,
243 Location object_class,
244 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000245 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000246 class_to_check_(class_to_check),
247 object_class_(object_class),
248 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000249
Alexandre Rames67555f72014-11-18 10:55:16 +0000250 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000251 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000252 DCHECK(instruction_->IsCheckCast()
253 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000254
255 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
256 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000257 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000258
259 // We're moving two locations to locations that could overlap, so we need a parallel
260 // move resolver.
261 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000262 codegen->EmitParallelMoves(
263 class_to_check_,
264 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
265 object_class_,
266 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000267
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000268 if (instruction_->IsInstanceOf()) {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000269 arm_codegen->InvokeRuntime(
270 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000271 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
272 } else {
273 DCHECK(instruction_->IsCheckCast());
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000274 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000275 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000277 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278 __ b(GetExitLabel());
279 }
280
281 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000282 HInstruction* const instruction_;
283 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000285 uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286
287 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
288};
289
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700290class DeoptimizationSlowPathARM : public SlowPathCodeARM {
291 public:
292 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
293 : instruction_(instruction) {}
294
295 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
296 __ Bind(GetEntryLabel());
297 SaveLiveRegisters(codegen, instruction_->GetLocations());
298 DCHECK(instruction_->IsDeoptimize());
299 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
300 uint32_t dex_pc = deoptimize->GetDexPc();
301 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
302 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
303 }
304
305 private:
306 HInstruction* const instruction_;
307 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
308};
309
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000310#undef __
311
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100312#undef __
313#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700314
315inline Condition ARMCondition(IfCondition cond) {
316 switch (cond) {
317 case kCondEQ: return EQ;
318 case kCondNE: return NE;
319 case kCondLT: return LT;
320 case kCondLE: return LE;
321 case kCondGT: return GT;
322 case kCondGE: return GE;
323 default:
324 LOG(FATAL) << "Unknown if condition";
325 }
326 return EQ; // Unreachable.
327}
328
329inline Condition ARMOppositeCondition(IfCondition cond) {
330 switch (cond) {
331 case kCondEQ: return NE;
332 case kCondNE: return EQ;
333 case kCondLT: return GE;
334 case kCondLE: return GT;
335 case kCondGT: return LE;
336 case kCondGE: return LT;
337 default:
338 LOG(FATAL) << "Unknown if condition";
339 }
340 return EQ; // Unreachable.
341}
342
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100343void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
344 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
345}
346
347void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000348 stream << ArmManagedRegister::FromSRegister(SRegister(reg));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100349}
350
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100351size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
352 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
353 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100354}
355
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100356size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
357 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
358 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100359}
360
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000361size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
362 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
363 return kArmWordSize;
364}
365
366size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
367 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
368 return kArmWordSize;
369}
370
Calin Juravle34166012014-12-19 17:22:29 +0000371CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000372 const ArmInstructionSetFeatures& isa_features,
373 const CompilerOptions& compiler_options)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000374 : CodeGenerator(graph,
375 kNumberOfCoreRegisters,
376 kNumberOfSRegisters,
377 kNumberOfRegisterPairs,
378 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
379 arraysize(kCoreCalleeSaves)),
380 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
381 arraysize(kFpuCalleeSaves)),
382 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100383 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100384 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100385 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100386 move_resolver_(graph->GetArena(), this),
Calin Juravle34166012014-12-19 17:22:29 +0000387 assembler_(true),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000388 isa_features_(isa_features) {
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000389 // Save the PC register to mimic Quick.
390 AddAllocatedRegister(Location::RegisterLocation(PC));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100391}
392
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100393Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100394 switch (type) {
395 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100396 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100397 ArmManagedRegister pair =
398 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100399 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
400 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
401
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100402 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
403 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100404 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100405 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100406 }
407
408 case Primitive::kPrimByte:
409 case Primitive::kPrimBoolean:
410 case Primitive::kPrimChar:
411 case Primitive::kPrimShort:
412 case Primitive::kPrimInt:
413 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100414 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100415 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100416 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
417 ArmManagedRegister current =
418 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
419 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100420 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100421 }
422 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100423 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100424 }
425
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000426 case Primitive::kPrimFloat: {
427 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100428 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100429 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100430
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000431 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000432 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
433 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000434 return Location::FpuRegisterPairLocation(reg, reg + 1);
435 }
436
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100437 case Primitive::kPrimVoid:
438 LOG(FATAL) << "Unreachable type " << type;
439 }
440
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100441 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100442}
443
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000444void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100445 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100446 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100447
448 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100449 blocked_core_registers_[SP] = true;
450 blocked_core_registers_[LR] = true;
451 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100452
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100453 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100454 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100455
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100456 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100457 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100458
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000459 if (is_baseline) {
460 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
461 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
462 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000463
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000464 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
465
466 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
467 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
468 }
469 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100470
471 UpdateBlockedPairRegisters();
472}
473
474void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
475 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
476 ArmManagedRegister current =
477 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
478 if (blocked_core_registers_[current.AsRegisterPairLow()]
479 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
480 blocked_register_pairs_[i] = true;
481 }
482 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100483}
484
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100485InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
486 : HGraphVisitor(graph),
487 assembler_(codegen->GetAssembler()),
488 codegen_(codegen) {}
489
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000490static uint32_t LeastSignificantBit(uint32_t mask) {
491 // ffs starts at 1.
492 return ffs(mask) - 1;
493}
494
495void CodeGeneratorARM::ComputeSpillMask() {
496 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000497 // Save one extra register for baseline. Note that on thumb2, there is no easy
498 // instruction to restore just the PC, so this actually helps both baseline
499 // and non-baseline to save and restore at least two registers at entry and exit.
500 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000501 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
502 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
503 // We use vpush and vpop for saving and restoring floating point registers, which take
504 // a SRegister and the number of registers to save/restore after that SRegister. We
505 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
506 // but in the range.
507 if (fpu_spill_mask_ != 0) {
508 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
509 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
510 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
511 fpu_spill_mask_ |= (1 << i);
512 }
513 }
514}
515
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000516void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000517 bool skip_overflow_check =
518 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000519 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000520 __ Bind(&frame_entry_label_);
521
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000522 if (HasEmptyFrame()) {
523 return;
524 }
525
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100526 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000527 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
528 __ LoadFromOffset(kLoadWord, IP, IP, 0);
529 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100530 }
531
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000532 // PC is in the list of callee-save to mimic Quick, but we need to push
533 // LR at entry instead.
534 __ PushList((core_spill_mask_ & (~(1 << PC))) | 1 << LR);
535 if (fpu_spill_mask_ != 0) {
536 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
537 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
538 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000539 __ AddConstant(SP, -(GetFrameSize() - FrameEntrySpillSize()));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100540 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000541}
542
543void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000544 if (HasEmptyFrame()) {
545 __ bx(LR);
546 return;
547 }
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()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100565
566 case Primitive::kPrimInt:
567 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100568 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100569 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100570
571 case Primitive::kPrimBoolean:
572 case Primitive::kPrimByte:
573 case Primitive::kPrimChar:
574 case Primitive::kPrimShort:
575 case Primitive::kPrimVoid:
576 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700577 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100578 }
579
580 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700581 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100582}
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();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000686}
687
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100688void CodeGeneratorARM::Move32(Location destination, Location source) {
689 if (source.Equals(destination)) {
690 return;
691 }
692 if (destination.IsRegister()) {
693 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000694 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100695 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000696 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100697 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000698 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100700 } else if (destination.IsFpuRegister()) {
701 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000702 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100703 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000704 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100705 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000706 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100707 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100708 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000709 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100710 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000711 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100712 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000713 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100714 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000715 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100716 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
717 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100718 }
719 }
720}
721
722void CodeGeneratorARM::Move64(Location destination, Location source) {
723 if (source.Equals(destination)) {
724 return;
725 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100726 if (destination.IsRegisterPair()) {
727 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000728 EmitParallelMoves(
729 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
730 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
731 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
732 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100733 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000734 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100735 } else {
736 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000737 DCHECK(ExpectedPairLayout(destination));
738 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
739 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100740 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000741 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100742 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000743 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
744 SP,
745 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100746 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000747 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100748 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100749 } else {
750 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100751 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000752 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100753 if (source.AsRegisterPairLow<Register>() == R1) {
754 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100755 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
756 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100757 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100758 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100759 SP, destination.GetStackIndex());
760 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000761 } else if (source.IsFpuRegisterPair()) {
762 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
763 SP,
764 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100765 } else {
766 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000767 EmitParallelMoves(
768 Location::StackSlot(source.GetStackIndex()),
769 Location::StackSlot(destination.GetStackIndex()),
770 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
771 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100772 }
773 }
774}
775
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100776void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100777 LocationSummary* locations = instruction->GetLocations();
778 if (locations != nullptr && locations->Out().Equals(location)) {
779 return;
780 }
781
Calin Juravlea21f5982014-11-13 15:53:04 +0000782 if (locations != nullptr && locations->Out().IsConstant()) {
783 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000784 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
785 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000786 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000787 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000788 } else {
789 DCHECK(location.IsStackSlot());
790 __ LoadImmediate(IP, value);
791 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
792 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000793 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000794 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000795 int64_t value = const_to_move->AsLongConstant()->GetValue();
796 if (location.IsRegisterPair()) {
797 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
798 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
799 } else {
800 DCHECK(location.IsDoubleStackSlot());
801 __ LoadImmediate(IP, Low32Bits(value));
802 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
803 __ LoadImmediate(IP, High32Bits(value));
804 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
805 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100806 }
Roland Levillain476df552014-10-09 17:51:36 +0100807 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
809 switch (instruction->GetType()) {
810 case Primitive::kPrimBoolean:
811 case Primitive::kPrimByte:
812 case Primitive::kPrimChar:
813 case Primitive::kPrimShort:
814 case Primitive::kPrimInt:
815 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100816 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100817 Move32(location, Location::StackSlot(stack_slot));
818 break;
819
820 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100821 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100822 Move64(location, Location::DoubleStackSlot(stack_slot));
823 break;
824
825 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100826 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100827 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000828 } else if (instruction->IsTemporary()) {
829 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000830 if (temp_location.IsStackSlot()) {
831 Move32(location, temp_location);
832 } else {
833 DCHECK(temp_location.IsDoubleStackSlot());
834 Move64(location, temp_location);
835 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000836 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100837 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100838 switch (instruction->GetType()) {
839 case Primitive::kPrimBoolean:
840 case Primitive::kPrimByte:
841 case Primitive::kPrimChar:
842 case Primitive::kPrimShort:
843 case Primitive::kPrimNot:
844 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100845 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100846 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100847 break;
848
849 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100850 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100851 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100852 break;
853
854 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100855 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100856 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000857 }
858}
859
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100860void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
861 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000862 uint32_t dex_pc,
863 SlowPathCode* slow_path) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100864 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
865 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000866 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100867 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();
David Brazdil46e2a392015-03-16 17:31:52 +0000887 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100888 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}
908
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700909void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
910 Label* true_target,
911 Label* false_target,
912 Label* always_true_target) {
913 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100914 if (cond->IsIntConstant()) {
915 // Constant condition, statically compared against 1.
916 int32_t cond_value = cond->AsIntConstant()->GetValue();
917 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700918 if (always_true_target != nullptr) {
919 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100920 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100921 return;
922 } else {
923 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100924 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100925 } else {
926 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
927 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700928 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
929 __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100930 ShifterOperand(0));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700931 __ b(true_target, NE);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100932 } else {
933 // Condition has not been materialized, use its inputs as the
934 // comparison and its condition as the branch condition.
935 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000936 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000937 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100938 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000939 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100940 } else {
941 DCHECK(locations->InAt(1).IsConstant());
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000942 HConstant* constant = locations->InAt(1).GetConstant();
943 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100944 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000945 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
946 __ cmp(left, operand);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100947 } else {
948 Register temp = IP;
949 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000950 __ cmp(left, ShifterOperand(temp));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100951 }
952 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700953 __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100954 }
Dave Allison20dfc792014-06-16 20:44:29 -0700955 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700956 if (false_target != nullptr) {
957 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000958 }
959}
960
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700961void LocationsBuilderARM::VisitIf(HIf* if_instr) {
962 LocationSummary* locations =
963 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
964 HInstruction* cond = if_instr->InputAt(0);
965 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
966 locations->SetInAt(0, Location::RequiresRegister());
967 }
968}
969
970void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
971 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
972 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
973 Label* always_true_target = true_target;
974 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
975 if_instr->IfTrueSuccessor())) {
976 always_true_target = nullptr;
977 }
978 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
979 if_instr->IfFalseSuccessor())) {
980 false_target = nullptr;
981 }
982 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
983}
984
985void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
986 LocationSummary* locations = new (GetGraph()->GetArena())
987 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
988 HInstruction* cond = deoptimize->InputAt(0);
989 DCHECK(cond->IsCondition());
990 if (cond->AsCondition()->NeedsMaterialization()) {
991 locations->SetInAt(0, Location::RequiresRegister());
992 }
993}
994
995void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
996 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
997 DeoptimizationSlowPathARM(deoptimize);
998 codegen_->AddSlowPath(slow_path);
999 Label* slow_path_entry = slow_path->GetEntryLabel();
1000 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1001}
Dave Allison20dfc792014-06-16 20:44:29 -07001002
1003void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001004 LocationSummary* locations =
1005 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001006 locations->SetInAt(0, Location::RequiresRegister());
1007 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001008 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001009 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001010 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001011}
1012
Dave Allison20dfc792014-06-16 20:44:29 -07001013void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001014 if (!comp->NeedsMaterialization()) return;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001015 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001016 Register left = locations->InAt(0).AsRegister<Register>();
1017
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001018 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001019 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001020 } else {
1021 DCHECK(locations->InAt(1).IsConstant());
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001022 int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001023 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001024 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
1025 __ cmp(left, operand);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001026 } else {
1027 Register temp = IP;
1028 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001029 __ cmp(left, ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001030 }
Dave Allison20dfc792014-06-16 20:44:29 -07001031 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001032 __ it(ARMCondition(comp->GetCondition()), kItElse);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001033 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001034 ARMCondition(comp->GetCondition()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001035 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001036 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -07001037}
1038
1039void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1040 VisitCondition(comp);
1041}
1042
1043void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1044 VisitCondition(comp);
1045}
1046
1047void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1048 VisitCondition(comp);
1049}
1050
1051void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1052 VisitCondition(comp);
1053}
1054
1055void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1056 VisitCondition(comp);
1057}
1058
1059void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1060 VisitCondition(comp);
1061}
1062
1063void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1064 VisitCondition(comp);
1065}
1066
1067void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1068 VisitCondition(comp);
1069}
1070
1071void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1072 VisitCondition(comp);
1073}
1074
1075void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1076 VisitCondition(comp);
1077}
1078
1079void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1080 VisitCondition(comp);
1081}
1082
1083void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1084 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001085}
1086
1087void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001088 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001089}
1090
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001091void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1092 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001093}
1094
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001095void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001096 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001097}
1098
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001099void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001100 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001101 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001102}
1103
1104void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001105 LocationSummary* locations =
1106 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001107 switch (store->InputAt(1)->GetType()) {
1108 case Primitive::kPrimBoolean:
1109 case Primitive::kPrimByte:
1110 case Primitive::kPrimChar:
1111 case Primitive::kPrimShort:
1112 case Primitive::kPrimInt:
1113 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001114 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1116 break;
1117
1118 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001119 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001120 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1121 break;
1122
1123 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001124 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001125 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001126}
1127
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001128void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001129 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001130}
1131
1132void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001133 LocationSummary* locations =
1134 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001135 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001136}
1137
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001138void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001139 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001140 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001141}
1142
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001143void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1144 LocationSummary* locations =
1145 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1146 locations->SetOut(Location::ConstantLocation(constant));
1147}
1148
1149void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1150 // Will be generated at use site.
1151 UNUSED(constant);
1152}
1153
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001154void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001155 LocationSummary* locations =
1156 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001157 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001158}
1159
1160void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1161 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001162 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001163}
1164
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001165void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1166 LocationSummary* locations =
1167 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1168 locations->SetOut(Location::ConstantLocation(constant));
1169}
1170
1171void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1172 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001173 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001174}
1175
1176void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1177 LocationSummary* locations =
1178 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1179 locations->SetOut(Location::ConstantLocation(constant));
1180}
1181
1182void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1183 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001184 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001185}
1186
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001187void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001188 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001189}
1190
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001191void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001192 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001193 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001194}
1195
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001196void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001197 LocationSummary* locations =
1198 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001199 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001200}
1201
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001202void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001203 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001204 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001205}
1206
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001207void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001208 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1209 codegen_->GetInstructionSetFeatures());
1210 if (intrinsic.TryDispatch(invoke)) {
1211 return;
1212 }
1213
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001214 HandleInvoke(invoke);
1215}
1216
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001217void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001218 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001219 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001220}
1221
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001222static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1223 if (invoke->GetLocations()->Intrinsified()) {
1224 IntrinsicCodeGeneratorARM intrinsic(codegen);
1225 intrinsic.Dispatch(invoke);
1226 return true;
1227 }
1228 return false;
1229}
1230
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001231void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001232 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1233 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001234 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001235
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001236 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1237
1238 codegen_->GenerateStaticOrDirectCall(invoke, temp);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001239 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001240}
1241
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001242void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001243 LocationSummary* locations =
1244 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001245 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001246
1247 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001248 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001249 HInstruction* input = invoke->InputAt(i);
1250 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1251 }
1252
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001253 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001254}
1255
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001256void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001257 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1258 codegen_->GetInstructionSetFeatures());
1259 if (intrinsic.TryDispatch(invoke)) {
1260 return;
1261 }
1262
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001263 HandleInvoke(invoke);
1264}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001265
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001266void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001267 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1268 return;
1269 }
1270
Roland Levillain271ab9c2014-11-27 15:23:57 +00001271 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001272 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1273 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1274 LocationSummary* locations = invoke->GetLocations();
1275 Location receiver = locations->InAt(0);
1276 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1277 // temp = object->GetClass();
1278 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001279 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1280 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001281 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001282 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001283 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001284 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001285 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001286 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001287 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001288 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001289 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001290 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001291 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001292 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001293 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001294 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001295}
1296
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001297void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1298 HandleInvoke(invoke);
1299 // Add the hidden argument.
1300 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1301}
1302
1303void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1304 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001305 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001306 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1307 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1308 LocationSummary* locations = invoke->GetLocations();
1309 Location receiver = locations->InAt(0);
1310 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1311
1312 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001313 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1314 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001315
1316 // temp = object->GetClass();
1317 if (receiver.IsStackSlot()) {
1318 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1319 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1320 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001321 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001322 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001323 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001324 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001325 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001326 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001327 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1328 // LR = temp->GetEntryPoint();
1329 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1330 // LR();
1331 __ blx(LR);
1332 DCHECK(!codegen_->IsLeafMethod());
1333 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1334}
1335
Roland Levillain88cb1752014-10-20 16:36:47 +01001336void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1337 LocationSummary* locations =
1338 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1339 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001340 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001341 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001342 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1343 break;
1344 }
1345 case Primitive::kPrimLong: {
1346 locations->SetInAt(0, Location::RequiresRegister());
1347 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001348 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001349 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001350
Roland Levillain88cb1752014-10-20 16:36:47 +01001351 case Primitive::kPrimFloat:
1352 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001353 locations->SetInAt(0, Location::RequiresFpuRegister());
1354 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001355 break;
1356
1357 default:
1358 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1359 }
1360}
1361
1362void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1363 LocationSummary* locations = neg->GetLocations();
1364 Location out = locations->Out();
1365 Location in = locations->InAt(0);
1366 switch (neg->GetResultType()) {
1367 case Primitive::kPrimInt:
1368 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001369 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001370 break;
1371
1372 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001373 DCHECK(in.IsRegisterPair());
1374 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1375 __ rsbs(out.AsRegisterPairLow<Register>(),
1376 in.AsRegisterPairLow<Register>(),
1377 ShifterOperand(0));
1378 // We cannot emit an RSC (Reverse Subtract with Carry)
1379 // instruction here, as it does not exist in the Thumb-2
1380 // instruction set. We use the following approach
1381 // using SBC and SUB instead.
1382 //
1383 // out.hi = -C
1384 __ sbc(out.AsRegisterPairHigh<Register>(),
1385 out.AsRegisterPairHigh<Register>(),
1386 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1387 // out.hi = out.hi - in.hi
1388 __ sub(out.AsRegisterPairHigh<Register>(),
1389 out.AsRegisterPairHigh<Register>(),
1390 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1391 break;
1392
Roland Levillain88cb1752014-10-20 16:36:47 +01001393 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001394 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001395 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001396 break;
1397
Roland Levillain88cb1752014-10-20 16:36:47 +01001398 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001399 DCHECK(in.IsFpuRegisterPair());
1400 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1401 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001402 break;
1403
1404 default:
1405 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1406 }
1407}
1408
Roland Levillaindff1f282014-11-05 14:15:05 +00001409void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001410 Primitive::Type result_type = conversion->GetResultType();
1411 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001412 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001413
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001414 // The float-to-long and double-to-long type conversions rely on a
1415 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001416 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001417 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1418 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001419 ? LocationSummary::kCall
1420 : LocationSummary::kNoCall;
1421 LocationSummary* locations =
1422 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1423
David Brazdilb2bd1c52015-03-25 11:17:37 +00001424 // The Java language does not allow treating boolean as an integral type but
1425 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001426
Roland Levillaindff1f282014-11-05 14:15:05 +00001427 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001428 case Primitive::kPrimByte:
1429 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001430 case Primitive::kPrimBoolean:
1431 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001432 case Primitive::kPrimShort:
1433 case Primitive::kPrimInt:
1434 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001435 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001436 locations->SetInAt(0, Location::RequiresRegister());
1437 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1438 break;
1439
1440 default:
1441 LOG(FATAL) << "Unexpected type conversion from " << input_type
1442 << " to " << result_type;
1443 }
1444 break;
1445
Roland Levillain01a8d712014-11-14 16:27:39 +00001446 case Primitive::kPrimShort:
1447 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001448 case Primitive::kPrimBoolean:
1449 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001450 case Primitive::kPrimByte:
1451 case Primitive::kPrimInt:
1452 case Primitive::kPrimChar:
1453 // Processing a Dex `int-to-short' instruction.
1454 locations->SetInAt(0, Location::RequiresRegister());
1455 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1456 break;
1457
1458 default:
1459 LOG(FATAL) << "Unexpected type conversion from " << input_type
1460 << " to " << result_type;
1461 }
1462 break;
1463
Roland Levillain946e1432014-11-11 17:35:19 +00001464 case Primitive::kPrimInt:
1465 switch (input_type) {
1466 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001467 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001468 locations->SetInAt(0, Location::Any());
1469 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1470 break;
1471
1472 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001473 // Processing a Dex `float-to-int' instruction.
1474 locations->SetInAt(0, Location::RequiresFpuRegister());
1475 locations->SetOut(Location::RequiresRegister());
1476 locations->AddTemp(Location::RequiresFpuRegister());
1477 break;
1478
Roland Levillain946e1432014-11-11 17:35:19 +00001479 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001480 // Processing a Dex `double-to-int' instruction.
1481 locations->SetInAt(0, Location::RequiresFpuRegister());
1482 locations->SetOut(Location::RequiresRegister());
1483 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001484 break;
1485
1486 default:
1487 LOG(FATAL) << "Unexpected type conversion from " << input_type
1488 << " to " << result_type;
1489 }
1490 break;
1491
Roland Levillaindff1f282014-11-05 14:15:05 +00001492 case Primitive::kPrimLong:
1493 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001494 case Primitive::kPrimBoolean:
1495 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001496 case Primitive::kPrimByte:
1497 case Primitive::kPrimShort:
1498 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001499 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001500 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001501 locations->SetInAt(0, Location::RequiresRegister());
1502 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1503 break;
1504
Roland Levillain624279f2014-12-04 11:54:28 +00001505 case Primitive::kPrimFloat: {
1506 // Processing a Dex `float-to-long' instruction.
1507 InvokeRuntimeCallingConvention calling_convention;
1508 locations->SetInAt(0, Location::FpuRegisterLocation(
1509 calling_convention.GetFpuRegisterAt(0)));
1510 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1511 break;
1512 }
1513
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001514 case Primitive::kPrimDouble: {
1515 // Processing a Dex `double-to-long' instruction.
1516 InvokeRuntimeCallingConvention calling_convention;
1517 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1518 calling_convention.GetFpuRegisterAt(0),
1519 calling_convention.GetFpuRegisterAt(1)));
1520 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001521 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001522 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001523
1524 default:
1525 LOG(FATAL) << "Unexpected type conversion from " << input_type
1526 << " to " << result_type;
1527 }
1528 break;
1529
Roland Levillain981e4542014-11-14 11:47:14 +00001530 case Primitive::kPrimChar:
1531 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001532 case Primitive::kPrimBoolean:
1533 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001534 case Primitive::kPrimByte:
1535 case Primitive::kPrimShort:
1536 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001537 // Processing a Dex `int-to-char' instruction.
1538 locations->SetInAt(0, Location::RequiresRegister());
1539 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1540 break;
1541
1542 default:
1543 LOG(FATAL) << "Unexpected type conversion from " << input_type
1544 << " to " << result_type;
1545 }
1546 break;
1547
Roland Levillaindff1f282014-11-05 14:15:05 +00001548 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001549 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001550 case Primitive::kPrimBoolean:
1551 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001552 case Primitive::kPrimByte:
1553 case Primitive::kPrimShort:
1554 case Primitive::kPrimInt:
1555 case Primitive::kPrimChar:
1556 // Processing a Dex `int-to-float' instruction.
1557 locations->SetInAt(0, Location::RequiresRegister());
1558 locations->SetOut(Location::RequiresFpuRegister());
1559 break;
1560
1561 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001562 // Processing a Dex `long-to-float' instruction.
1563 locations->SetInAt(0, Location::RequiresRegister());
1564 locations->SetOut(Location::RequiresFpuRegister());
1565 locations->AddTemp(Location::RequiresRegister());
1566 locations->AddTemp(Location::RequiresRegister());
1567 locations->AddTemp(Location::RequiresFpuRegister());
1568 locations->AddTemp(Location::RequiresFpuRegister());
1569 break;
1570
Roland Levillaincff13742014-11-17 14:32:17 +00001571 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001572 // Processing a Dex `double-to-float' instruction.
1573 locations->SetInAt(0, Location::RequiresFpuRegister());
1574 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001575 break;
1576
1577 default:
1578 LOG(FATAL) << "Unexpected type conversion from " << input_type
1579 << " to " << result_type;
1580 };
1581 break;
1582
Roland Levillaindff1f282014-11-05 14:15:05 +00001583 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001584 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001585 case Primitive::kPrimBoolean:
1586 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001587 case Primitive::kPrimByte:
1588 case Primitive::kPrimShort:
1589 case Primitive::kPrimInt:
1590 case Primitive::kPrimChar:
1591 // Processing a Dex `int-to-double' instruction.
1592 locations->SetInAt(0, Location::RequiresRegister());
1593 locations->SetOut(Location::RequiresFpuRegister());
1594 break;
1595
1596 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001597 // Processing a Dex `long-to-double' instruction.
1598 locations->SetInAt(0, Location::RequiresRegister());
1599 locations->SetOut(Location::RequiresFpuRegister());
1600 locations->AddTemp(Location::RequiresRegister());
1601 locations->AddTemp(Location::RequiresRegister());
1602 locations->AddTemp(Location::RequiresFpuRegister());
1603 break;
1604
Roland Levillaincff13742014-11-17 14:32:17 +00001605 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001606 // Processing a Dex `float-to-double' instruction.
1607 locations->SetInAt(0, Location::RequiresFpuRegister());
1608 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001609 break;
1610
1611 default:
1612 LOG(FATAL) << "Unexpected type conversion from " << input_type
1613 << " to " << result_type;
1614 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001615 break;
1616
1617 default:
1618 LOG(FATAL) << "Unexpected type conversion from " << input_type
1619 << " to " << result_type;
1620 }
1621}
1622
1623void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1624 LocationSummary* locations = conversion->GetLocations();
1625 Location out = locations->Out();
1626 Location in = locations->InAt(0);
1627 Primitive::Type result_type = conversion->GetResultType();
1628 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001629 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001630 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001631 case Primitive::kPrimByte:
1632 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001633 case Primitive::kPrimBoolean:
1634 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001635 case Primitive::kPrimShort:
1636 case Primitive::kPrimInt:
1637 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001638 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001639 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001640 break;
1641
1642 default:
1643 LOG(FATAL) << "Unexpected type conversion from " << input_type
1644 << " to " << result_type;
1645 }
1646 break;
1647
Roland Levillain01a8d712014-11-14 16:27:39 +00001648 case Primitive::kPrimShort:
1649 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001650 case Primitive::kPrimBoolean:
1651 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001652 case Primitive::kPrimByte:
1653 case Primitive::kPrimInt:
1654 case Primitive::kPrimChar:
1655 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001656 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001657 break;
1658
1659 default:
1660 LOG(FATAL) << "Unexpected type conversion from " << input_type
1661 << " to " << result_type;
1662 }
1663 break;
1664
Roland Levillain946e1432014-11-11 17:35:19 +00001665 case Primitive::kPrimInt:
1666 switch (input_type) {
1667 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001668 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001669 DCHECK(out.IsRegister());
1670 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001671 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001672 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001673 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001674 } else {
1675 DCHECK(in.IsConstant());
1676 DCHECK(in.GetConstant()->IsLongConstant());
1677 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001678 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001679 }
1680 break;
1681
Roland Levillain3f8f9362014-12-02 17:45:01 +00001682 case Primitive::kPrimFloat: {
1683 // Processing a Dex `float-to-int' instruction.
1684 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1685 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1686 __ vcvtis(temp, temp);
1687 __ vmovrs(out.AsRegister<Register>(), temp);
1688 break;
1689 }
1690
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001691 case Primitive::kPrimDouble: {
1692 // Processing a Dex `double-to-int' instruction.
1693 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1694 DRegister temp_d = FromLowSToD(temp_s);
1695 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1696 __ vcvtid(temp_s, temp_d);
1697 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001698 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001699 }
Roland Levillain946e1432014-11-11 17:35:19 +00001700
1701 default:
1702 LOG(FATAL) << "Unexpected type conversion from " << input_type
1703 << " to " << result_type;
1704 }
1705 break;
1706
Roland Levillaindff1f282014-11-05 14:15:05 +00001707 case Primitive::kPrimLong:
1708 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001709 case Primitive::kPrimBoolean:
1710 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001711 case Primitive::kPrimByte:
1712 case Primitive::kPrimShort:
1713 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001714 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001715 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001716 DCHECK(out.IsRegisterPair());
1717 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001718 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001719 // Sign extension.
1720 __ Asr(out.AsRegisterPairHigh<Register>(),
1721 out.AsRegisterPairLow<Register>(),
1722 31);
1723 break;
1724
1725 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001726 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00001727 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1728 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001729 conversion->GetDexPc(),
1730 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00001731 break;
1732
Roland Levillaindff1f282014-11-05 14:15:05 +00001733 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001734 // Processing a Dex `double-to-long' instruction.
1735 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1736 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001737 conversion->GetDexPc(),
1738 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00001739 break;
1740
1741 default:
1742 LOG(FATAL) << "Unexpected type conversion from " << input_type
1743 << " to " << result_type;
1744 }
1745 break;
1746
Roland Levillain981e4542014-11-14 11:47:14 +00001747 case Primitive::kPrimChar:
1748 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001749 case Primitive::kPrimBoolean:
1750 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001751 case Primitive::kPrimByte:
1752 case Primitive::kPrimShort:
1753 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001754 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001755 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00001756 break;
1757
1758 default:
1759 LOG(FATAL) << "Unexpected type conversion from " << input_type
1760 << " to " << result_type;
1761 }
1762 break;
1763
Roland Levillaindff1f282014-11-05 14:15:05 +00001764 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001765 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001766 case Primitive::kPrimBoolean:
1767 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001768 case Primitive::kPrimByte:
1769 case Primitive::kPrimShort:
1770 case Primitive::kPrimInt:
1771 case Primitive::kPrimChar: {
1772 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001773 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1774 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001775 break;
1776 }
1777
Roland Levillain6d0e4832014-11-27 18:31:21 +00001778 case Primitive::kPrimLong: {
1779 // Processing a Dex `long-to-float' instruction.
1780 Register low = in.AsRegisterPairLow<Register>();
1781 Register high = in.AsRegisterPairHigh<Register>();
1782 SRegister output = out.AsFpuRegister<SRegister>();
1783 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1784 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1785 SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1786 DRegister temp1_d = FromLowSToD(temp1_s);
1787 SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
1788 DRegister temp2_d = FromLowSToD(temp2_s);
1789
1790 // Operations use doubles for precision reasons (each 32-bit
1791 // half of a long fits in the 53-bit mantissa of a double,
1792 // but not in the 24-bit mantissa of a float). This is
1793 // especially important for the low bits. The result is
1794 // eventually converted to float.
1795
1796 // temp1_d = int-to-double(high)
1797 __ vmovsr(temp1_s, high);
1798 __ vcvtdi(temp1_d, temp1_s);
1799 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1800 // as an immediate value into `temp2_d` does not work, as
1801 // this instruction only transfers 8 significant bits of its
1802 // immediate operand. Instead, use two 32-bit core
1803 // registers to load `k2Pow32EncodingForDouble` into
1804 // `temp2_d`.
1805 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1806 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1807 __ vmovdrr(temp2_d, constant_low, constant_high);
1808 // temp1_d = temp1_d * 2^32
1809 __ vmuld(temp1_d, temp1_d, temp2_d);
1810 // temp2_d = unsigned-to-double(low)
1811 __ vmovsr(temp2_s, low);
1812 __ vcvtdu(temp2_d, temp2_s);
1813 // temp1_d = temp1_d + temp2_d
1814 __ vaddd(temp1_d, temp1_d, temp2_d);
1815 // output = double-to-float(temp1_d);
1816 __ vcvtsd(output, temp1_d);
1817 break;
1818 }
1819
Roland Levillaincff13742014-11-17 14:32:17 +00001820 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001821 // Processing a Dex `double-to-float' instruction.
1822 __ vcvtsd(out.AsFpuRegister<SRegister>(),
1823 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00001824 break;
1825
1826 default:
1827 LOG(FATAL) << "Unexpected type conversion from " << input_type
1828 << " to " << result_type;
1829 };
1830 break;
1831
Roland Levillaindff1f282014-11-05 14:15:05 +00001832 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001833 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001834 case Primitive::kPrimBoolean:
1835 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001836 case Primitive::kPrimByte:
1837 case Primitive::kPrimShort:
1838 case Primitive::kPrimInt:
1839 case Primitive::kPrimChar: {
1840 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001841 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001842 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1843 out.AsFpuRegisterPairLow<SRegister>());
1844 break;
1845 }
1846
Roland Levillain647b9ed2014-11-27 12:06:00 +00001847 case Primitive::kPrimLong: {
1848 // Processing a Dex `long-to-double' instruction.
1849 Register low = in.AsRegisterPairLow<Register>();
1850 Register high = in.AsRegisterPairHigh<Register>();
1851 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1852 DRegister out_d = FromLowSToD(out_s);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001853 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1854 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001855 SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1856 DRegister temp_d = FromLowSToD(temp_s);
1857
Roland Levillain647b9ed2014-11-27 12:06:00 +00001858 // out_d = int-to-double(high)
1859 __ vmovsr(out_s, high);
1860 __ vcvtdi(out_d, out_s);
Roland Levillain6d0e4832014-11-27 18:31:21 +00001861 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1862 // as an immediate value into `temp_d` does not work, as
1863 // this instruction only transfers 8 significant bits of its
1864 // immediate operand. Instead, use two 32-bit core
1865 // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
1866 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1867 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001868 __ vmovdrr(temp_d, constant_low, constant_high);
1869 // out_d = out_d * 2^32
1870 __ vmuld(out_d, out_d, temp_d);
1871 // temp_d = unsigned-to-double(low)
1872 __ vmovsr(temp_s, low);
1873 __ vcvtdu(temp_d, temp_s);
1874 // out_d = out_d + temp_d
1875 __ vaddd(out_d, out_d, temp_d);
1876 break;
1877 }
1878
Roland Levillaincff13742014-11-17 14:32:17 +00001879 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001880 // Processing a Dex `float-to-double' instruction.
1881 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1882 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001883 break;
1884
1885 default:
1886 LOG(FATAL) << "Unexpected type conversion from " << input_type
1887 << " to " << result_type;
1888 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001889 break;
1890
1891 default:
1892 LOG(FATAL) << "Unexpected type conversion from " << input_type
1893 << " to " << result_type;
1894 }
1895}
1896
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001897void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001898 LocationSummary* locations =
1899 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001900 switch (add->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(add->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());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001911 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001912 break;
1913 }
1914
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001915 case Primitive::kPrimFloat:
1916 case Primitive::kPrimDouble: {
1917 locations->SetInAt(0, Location::RequiresFpuRegister());
1918 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001919 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001920 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001921 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001922
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001923 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001924 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001925 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001926}
1927
1928void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1929 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001930 Location out = locations->Out();
1931 Location first = locations->InAt(0);
1932 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001933 switch (add->GetResultType()) {
1934 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001935 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001936 __ add(out.AsRegister<Register>(),
1937 first.AsRegister<Register>(),
1938 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001939 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001940 __ AddConstant(out.AsRegister<Register>(),
1941 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001942 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001943 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001944 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001945
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001946 case Primitive::kPrimLong: {
1947 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001948 __ adds(out.AsRegisterPairLow<Register>(),
1949 first.AsRegisterPairLow<Register>(),
1950 ShifterOperand(second.AsRegisterPairLow<Register>()));
1951 __ adc(out.AsRegisterPairHigh<Register>(),
1952 first.AsRegisterPairHigh<Register>(),
1953 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001954 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001955 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001956
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001957 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00001958 __ vadds(out.AsFpuRegister<SRegister>(),
1959 first.AsFpuRegister<SRegister>(),
1960 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001961 break;
1962
1963 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001964 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1965 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1966 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001967 break;
1968
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001969 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001970 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001971 }
1972}
1973
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001974void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001975 LocationSummary* locations =
1976 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001977 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001978 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001979 locations->SetInAt(0, Location::RequiresRegister());
1980 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001981 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1982 break;
1983 }
1984
1985 case Primitive::kPrimLong: {
1986 locations->SetInAt(0, Location::RequiresRegister());
1987 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001988 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001989 break;
1990 }
Calin Juravle11351682014-10-23 15:38:15 +01001991 case Primitive::kPrimFloat:
1992 case Primitive::kPrimDouble: {
1993 locations->SetInAt(0, Location::RequiresFpuRegister());
1994 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001995 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001996 break;
Calin Juravle11351682014-10-23 15:38:15 +01001997 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001998 default:
Calin Juravle11351682014-10-23 15:38:15 +01001999 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002000 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002001}
2002
2003void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2004 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002005 Location out = locations->Out();
2006 Location first = locations->InAt(0);
2007 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002008 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002009 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002010 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002011 __ sub(out.AsRegister<Register>(),
2012 first.AsRegister<Register>(),
2013 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002014 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002015 __ AddConstant(out.AsRegister<Register>(),
2016 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002017 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002018 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002019 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002020 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002021
Calin Juravle11351682014-10-23 15:38:15 +01002022 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002023 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002024 __ subs(out.AsRegisterPairLow<Register>(),
2025 first.AsRegisterPairLow<Register>(),
2026 ShifterOperand(second.AsRegisterPairLow<Register>()));
2027 __ sbc(out.AsRegisterPairHigh<Register>(),
2028 first.AsRegisterPairHigh<Register>(),
2029 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002030 break;
Calin Juravle11351682014-10-23 15:38:15 +01002031 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002032
Calin Juravle11351682014-10-23 15:38:15 +01002033 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002034 __ vsubs(out.AsFpuRegister<SRegister>(),
2035 first.AsFpuRegister<SRegister>(),
2036 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002037 break;
Calin Juravle11351682014-10-23 15:38:15 +01002038 }
2039
2040 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002041 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2042 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2043 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002044 break;
2045 }
2046
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002047
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002048 default:
Calin Juravle11351682014-10-23 15:38:15 +01002049 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002050 }
2051}
2052
Calin Juravle34bacdf2014-10-07 20:23:36 +01002053void LocationsBuilderARM::VisitMul(HMul* mul) {
2054 LocationSummary* locations =
2055 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2056 switch (mul->GetResultType()) {
2057 case Primitive::kPrimInt:
2058 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002059 locations->SetInAt(0, Location::RequiresRegister());
2060 locations->SetInAt(1, Location::RequiresRegister());
2061 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002062 break;
2063 }
2064
Calin Juravleb5bfa962014-10-21 18:02:24 +01002065 case Primitive::kPrimFloat:
2066 case Primitive::kPrimDouble: {
2067 locations->SetInAt(0, Location::RequiresFpuRegister());
2068 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002069 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002070 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002071 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002072
2073 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002074 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002075 }
2076}
2077
2078void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2079 LocationSummary* locations = mul->GetLocations();
2080 Location out = locations->Out();
2081 Location first = locations->InAt(0);
2082 Location second = locations->InAt(1);
2083 switch (mul->GetResultType()) {
2084 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002085 __ mul(out.AsRegister<Register>(),
2086 first.AsRegister<Register>(),
2087 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002088 break;
2089 }
2090 case Primitive::kPrimLong: {
2091 Register out_hi = out.AsRegisterPairHigh<Register>();
2092 Register out_lo = out.AsRegisterPairLow<Register>();
2093 Register in1_hi = first.AsRegisterPairHigh<Register>();
2094 Register in1_lo = first.AsRegisterPairLow<Register>();
2095 Register in2_hi = second.AsRegisterPairHigh<Register>();
2096 Register in2_lo = second.AsRegisterPairLow<Register>();
2097
2098 // Extra checks to protect caused by the existence of R1_R2.
2099 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2100 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2101 DCHECK_NE(out_hi, in1_lo);
2102 DCHECK_NE(out_hi, in2_lo);
2103
2104 // input: in1 - 64 bits, in2 - 64 bits
2105 // output: out
2106 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2107 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2108 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2109
2110 // IP <- in1.lo * in2.hi
2111 __ mul(IP, in1_lo, in2_hi);
2112 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2113 __ mla(out_hi, in1_hi, in2_lo, IP);
2114 // out.lo <- (in1.lo * in2.lo)[31:0];
2115 __ umull(out_lo, IP, in1_lo, in2_lo);
2116 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2117 __ add(out_hi, out_hi, ShifterOperand(IP));
2118 break;
2119 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002120
2121 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002122 __ vmuls(out.AsFpuRegister<SRegister>(),
2123 first.AsFpuRegister<SRegister>(),
2124 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002125 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002126 }
2127
2128 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002129 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2130 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2131 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002132 break;
2133 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002134
2135 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002136 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002137 }
2138}
2139
Calin Juravle7c4954d2014-10-28 16:57:40 +00002140void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002141 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2142 if (div->GetResultType() == Primitive::kPrimLong) {
2143 // pLdiv runtime call.
2144 call_kind = LocationSummary::kCall;
2145 } else if (div->GetResultType() == Primitive::kPrimInt &&
2146 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2147 // pIdivmod runtime call.
2148 call_kind = LocationSummary::kCall;
2149 }
2150
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002151 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2152
Calin Juravle7c4954d2014-10-28 16:57:40 +00002153 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002154 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002155 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2156 locations->SetInAt(0, Location::RequiresRegister());
2157 locations->SetInAt(1, Location::RequiresRegister());
2158 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2159 } else {
2160 InvokeRuntimeCallingConvention calling_convention;
2161 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2162 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2163 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2164 // we only need the former.
2165 locations->SetOut(Location::RegisterLocation(R0));
2166 }
Calin Juravled0d48522014-11-04 16:40:20 +00002167 break;
2168 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002169 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002170 InvokeRuntimeCallingConvention calling_convention;
2171 locations->SetInAt(0, Location::RegisterPairLocation(
2172 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2173 locations->SetInAt(1, Location::RegisterPairLocation(
2174 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002175 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002176 break;
2177 }
2178 case Primitive::kPrimFloat:
2179 case Primitive::kPrimDouble: {
2180 locations->SetInAt(0, Location::RequiresFpuRegister());
2181 locations->SetInAt(1, Location::RequiresFpuRegister());
2182 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2183 break;
2184 }
2185
2186 default:
2187 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2188 }
2189}
2190
2191void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2192 LocationSummary* locations = div->GetLocations();
2193 Location out = locations->Out();
2194 Location first = locations->InAt(0);
2195 Location second = locations->InAt(1);
2196
2197 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002198 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002199 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2200 __ sdiv(out.AsRegister<Register>(),
2201 first.AsRegister<Register>(),
2202 second.AsRegister<Register>());
2203 } else {
2204 InvokeRuntimeCallingConvention calling_convention;
2205 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2206 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2207 DCHECK_EQ(R0, out.AsRegister<Register>());
2208
2209 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2210 }
Calin Juravled0d48522014-11-04 16:40:20 +00002211 break;
2212 }
2213
Calin Juravle7c4954d2014-10-28 16:57:40 +00002214 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002215 InvokeRuntimeCallingConvention calling_convention;
2216 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2217 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2218 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2219 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2220 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002221 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002222
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002223 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002224 break;
2225 }
2226
2227 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002228 __ vdivs(out.AsFpuRegister<SRegister>(),
2229 first.AsFpuRegister<SRegister>(),
2230 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002231 break;
2232 }
2233
2234 case Primitive::kPrimDouble: {
2235 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2236 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2237 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2238 break;
2239 }
2240
2241 default:
2242 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2243 }
2244}
2245
Calin Juravlebacfec32014-11-14 15:54:36 +00002246void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002247 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002248
2249 // Most remainders are implemented in the runtime.
2250 LocationSummary::CallKind call_kind = LocationSummary::kCall;
2251 if (rem->GetResultType() == Primitive::kPrimInt &&
2252 codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2253 // Have hardware divide instruction for int, do it with three instructions.
2254 call_kind = LocationSummary::kNoCall;
2255 }
2256
Calin Juravlebacfec32014-11-14 15:54:36 +00002257 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2258
Calin Juravled2ec87d2014-12-08 14:24:46 +00002259 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002260 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002261 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2262 locations->SetInAt(0, Location::RequiresRegister());
2263 locations->SetInAt(1, Location::RequiresRegister());
2264 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2265 locations->AddTemp(Location::RequiresRegister());
2266 } else {
2267 InvokeRuntimeCallingConvention calling_convention;
2268 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2269 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2270 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2271 // we only need the latter.
2272 locations->SetOut(Location::RegisterLocation(R1));
2273 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002274 break;
2275 }
2276 case Primitive::kPrimLong: {
2277 InvokeRuntimeCallingConvention calling_convention;
2278 locations->SetInAt(0, Location::RegisterPairLocation(
2279 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2280 locations->SetInAt(1, Location::RegisterPairLocation(
2281 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2282 // The runtime helper puts the output in R2,R3.
2283 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2284 break;
2285 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002286 case Primitive::kPrimFloat: {
2287 InvokeRuntimeCallingConvention calling_convention;
2288 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2289 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2290 locations->SetOut(Location::FpuRegisterLocation(S0));
2291 break;
2292 }
2293
Calin Juravlebacfec32014-11-14 15:54:36 +00002294 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002295 InvokeRuntimeCallingConvention calling_convention;
2296 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2297 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2298 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2299 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2300 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002301 break;
2302 }
2303
2304 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002305 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002306 }
2307}
2308
2309void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2310 LocationSummary* locations = rem->GetLocations();
2311 Location out = locations->Out();
2312 Location first = locations->InAt(0);
2313 Location second = locations->InAt(1);
2314
Calin Juravled2ec87d2014-12-08 14:24:46 +00002315 Primitive::Type type = rem->GetResultType();
2316 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002317 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002318 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2319 Register reg1 = first.AsRegister<Register>();
2320 Register reg2 = second.AsRegister<Register>();
2321 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002322
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002323 // temp = reg1 / reg2 (integer division)
2324 // temp = temp * reg2
2325 // dest = reg1 - temp
2326 __ sdiv(temp, reg1, reg2);
2327 __ mul(temp, temp, reg2);
2328 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2329 } else {
2330 InvokeRuntimeCallingConvention calling_convention;
2331 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2332 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2333 DCHECK_EQ(R1, out.AsRegister<Register>());
2334
2335 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2336 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002337 break;
2338 }
2339
2340 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002341 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002342 break;
2343 }
2344
Calin Juravled2ec87d2014-12-08 14:24:46 +00002345 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002346 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002347 break;
2348 }
2349
Calin Juravlebacfec32014-11-14 15:54:36 +00002350 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002351 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002352 break;
2353 }
2354
2355 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002356 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002357 }
2358}
2359
Calin Juravled0d48522014-11-04 16:40:20 +00002360void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2361 LocationSummary* locations =
2362 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002363 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002364 if (instruction->HasUses()) {
2365 locations->SetOut(Location::SameAsFirstInput());
2366 }
2367}
2368
2369void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2370 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2371 codegen_->AddSlowPath(slow_path);
2372
2373 LocationSummary* locations = instruction->GetLocations();
2374 Location value = locations->InAt(0);
2375
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002376 switch (instruction->GetType()) {
2377 case Primitive::kPrimInt: {
2378 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002379 __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002380 __ b(slow_path->GetEntryLabel(), EQ);
2381 } else {
2382 DCHECK(value.IsConstant()) << value;
2383 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2384 __ b(slow_path->GetEntryLabel());
2385 }
2386 }
2387 break;
2388 }
2389 case Primitive::kPrimLong: {
2390 if (value.IsRegisterPair()) {
2391 __ orrs(IP,
2392 value.AsRegisterPairLow<Register>(),
2393 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2394 __ b(slow_path->GetEntryLabel(), EQ);
2395 } else {
2396 DCHECK(value.IsConstant()) << value;
2397 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2398 __ b(slow_path->GetEntryLabel());
2399 }
2400 }
2401 break;
2402 default:
2403 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2404 }
2405 }
Calin Juravled0d48522014-11-04 16:40:20 +00002406}
2407
Calin Juravle9aec02f2014-11-18 23:06:35 +00002408void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2409 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2410
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002411 LocationSummary* locations =
2412 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002413
2414 switch (op->GetResultType()) {
2415 case Primitive::kPrimInt: {
2416 locations->SetInAt(0, Location::RequiresRegister());
2417 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002418 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002419 break;
2420 }
2421 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002422 locations->SetInAt(0, Location::RequiresRegister());
2423 locations->SetInAt(1, Location::RequiresRegister());
2424 locations->AddTemp(Location::RequiresRegister());
2425 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002426 break;
2427 }
2428 default:
2429 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2430 }
2431}
2432
2433void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2434 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2435
2436 LocationSummary* locations = op->GetLocations();
2437 Location out = locations->Out();
2438 Location first = locations->InAt(0);
2439 Location second = locations->InAt(1);
2440
2441 Primitive::Type type = op->GetResultType();
2442 switch (type) {
2443 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002444 Register out_reg = out.AsRegister<Register>();
2445 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002446 // Arm doesn't mask the shift count so we need to do it ourselves.
2447 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002448 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002449 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2450 if (op->IsShl()) {
2451 __ Lsl(out_reg, first_reg, second_reg);
2452 } else if (op->IsShr()) {
2453 __ Asr(out_reg, first_reg, second_reg);
2454 } else {
2455 __ Lsr(out_reg, first_reg, second_reg);
2456 }
2457 } else {
2458 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2459 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2460 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2461 __ Mov(out_reg, first_reg);
2462 } else if (op->IsShl()) {
2463 __ Lsl(out_reg, first_reg, shift_value);
2464 } else if (op->IsShr()) {
2465 __ Asr(out_reg, first_reg, shift_value);
2466 } else {
2467 __ Lsr(out_reg, first_reg, shift_value);
2468 }
2469 }
2470 break;
2471 }
2472 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002473 Register o_h = out.AsRegisterPairHigh<Register>();
2474 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002475
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002476 Register temp = locations->GetTemp(0).AsRegister<Register>();
2477
2478 Register high = first.AsRegisterPairHigh<Register>();
2479 Register low = first.AsRegisterPairLow<Register>();
2480
2481 Register second_reg = second.AsRegister<Register>();
2482
Calin Juravle9aec02f2014-11-18 23:06:35 +00002483 if (op->IsShl()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002484 // Shift the high part
2485 __ and_(second_reg, second_reg, ShifterOperand(63));
2486 __ Lsl(o_h, high, second_reg);
2487 // Shift the low part and `or` what overflew on the high part
2488 __ rsb(temp, second_reg, ShifterOperand(32));
2489 __ Lsr(temp, low, temp);
2490 __ orr(o_h, o_h, ShifterOperand(temp));
2491 // If the shift is > 32 bits, override the high part
2492 __ subs(temp, second_reg, ShifterOperand(32));
2493 __ it(PL);
2494 __ Lsl(o_h, low, temp, false, PL);
2495 // Shift the low part
2496 __ Lsl(o_l, low, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002497 } else if (op->IsShr()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002498 // Shift the low part
2499 __ and_(second_reg, second_reg, ShifterOperand(63));
2500 __ Lsr(o_l, low, second_reg);
2501 // Shift the high part and `or` what underflew on the low part
2502 __ rsb(temp, second_reg, ShifterOperand(32));
2503 __ Lsl(temp, high, temp);
2504 __ orr(o_l, o_l, ShifterOperand(temp));
2505 // If the shift is > 32 bits, override the low part
2506 __ subs(temp, second_reg, ShifterOperand(32));
2507 __ it(PL);
2508 __ Asr(o_l, high, temp, false, PL);
2509 // Shift the high part
2510 __ Asr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002511 } else {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002512 // same as Shr except we use `Lsr`s and not `Asr`s
2513 __ and_(second_reg, second_reg, ShifterOperand(63));
2514 __ Lsr(o_l, low, second_reg);
2515 __ rsb(temp, second_reg, ShifterOperand(32));
2516 __ Lsl(temp, high, temp);
2517 __ orr(o_l, o_l, ShifterOperand(temp));
2518 __ subs(temp, second_reg, ShifterOperand(32));
2519 __ it(PL);
2520 __ Lsr(o_l, high, temp, false, PL);
2521 __ Lsr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002522 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002523 break;
2524 }
2525 default:
2526 LOG(FATAL) << "Unexpected operation type " << type;
2527 }
2528}
2529
2530void LocationsBuilderARM::VisitShl(HShl* shl) {
2531 HandleShift(shl);
2532}
2533
2534void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2535 HandleShift(shl);
2536}
2537
2538void LocationsBuilderARM::VisitShr(HShr* shr) {
2539 HandleShift(shr);
2540}
2541
2542void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2543 HandleShift(shr);
2544}
2545
2546void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2547 HandleShift(ushr);
2548}
2549
2550void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2551 HandleShift(ushr);
2552}
2553
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002554void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002555 LocationSummary* locations =
2556 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002557 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002558 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2559 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2560 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002561}
2562
2563void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2564 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002565 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002566 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002567 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2568 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002569 instruction->GetDexPc(),
2570 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002571}
2572
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002573void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2574 LocationSummary* locations =
2575 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2576 InvokeRuntimeCallingConvention calling_convention;
2577 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002578 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002579 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002580 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002581}
2582
2583void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2584 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002585 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002586 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002587 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2588 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002589 instruction->GetDexPc(),
2590 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002591}
2592
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002593void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002594 LocationSummary* locations =
2595 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002596 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2597 if (location.IsStackSlot()) {
2598 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2599 } else if (location.IsDoubleStackSlot()) {
2600 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002601 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002602 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002603}
2604
2605void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002606 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002607 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002608}
2609
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002610void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002611 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002612 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002613 locations->SetInAt(0, Location::RequiresRegister());
2614 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002615}
2616
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002617void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2618 LocationSummary* locations = not_->GetLocations();
2619 Location out = locations->Out();
2620 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002621 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002622 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002623 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002624 break;
2625
2626 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002627 __ mvn(out.AsRegisterPairLow<Register>(),
2628 ShifterOperand(in.AsRegisterPairLow<Register>()));
2629 __ mvn(out.AsRegisterPairHigh<Register>(),
2630 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002631 break;
2632
2633 default:
2634 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2635 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002636}
2637
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002638void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002639 LocationSummary* locations =
2640 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002641 switch (compare->InputAt(0)->GetType()) {
2642 case Primitive::kPrimLong: {
2643 locations->SetInAt(0, Location::RequiresRegister());
2644 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002645 // Output overlaps because it is written before doing the low comparison.
2646 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00002647 break;
2648 }
2649 case Primitive::kPrimFloat:
2650 case Primitive::kPrimDouble: {
2651 locations->SetInAt(0, Location::RequiresFpuRegister());
2652 locations->SetInAt(1, Location::RequiresFpuRegister());
2653 locations->SetOut(Location::RequiresRegister());
2654 break;
2655 }
2656 default:
2657 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2658 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002659}
2660
2661void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002662 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002663 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002664 Location left = locations->InAt(0);
2665 Location right = locations->InAt(1);
2666
2667 Label less, greater, done;
2668 Primitive::Type type = compare->InputAt(0)->GetType();
2669 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002670 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002671 __ cmp(left.AsRegisterPairHigh<Register>(),
2672 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002673 __ b(&less, LT);
2674 __ b(&greater, GT);
Calin Juravleddb7df22014-11-25 20:56:51 +00002675 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2676 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002677 __ cmp(left.AsRegisterPairLow<Register>(),
2678 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00002679 break;
2680 }
2681 case Primitive::kPrimFloat:
2682 case Primitive::kPrimDouble: {
2683 __ LoadImmediate(out, 0);
2684 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002685 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002686 } else {
2687 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2688 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2689 }
2690 __ vmstat(); // transfer FP status register to ARM APSR.
2691 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002692 break;
2693 }
2694 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002695 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002696 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002697 __ b(&done, EQ);
2698 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats.
2699
2700 __ Bind(&greater);
2701 __ LoadImmediate(out, 1);
2702 __ b(&done);
2703
2704 __ Bind(&less);
2705 __ LoadImmediate(out, -1);
2706
2707 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002708}
2709
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002710void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002711 LocationSummary* locations =
2712 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002713 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2714 locations->SetInAt(i, Location::Any());
2715 }
2716 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002717}
2718
2719void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002720 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002721 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002722}
2723
Calin Juravle52c48962014-12-16 17:02:57 +00002724void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2725 // TODO (ported from quick): revisit Arm barrier kinds
2726 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings
2727 switch (kind) {
2728 case MemBarrierKind::kAnyStore:
2729 case MemBarrierKind::kLoadAny:
2730 case MemBarrierKind::kAnyAny: {
2731 flavour = DmbOptions::ISH;
2732 break;
2733 }
2734 case MemBarrierKind::kStoreStore: {
2735 flavour = DmbOptions::ISHST;
2736 break;
2737 }
2738 default:
2739 LOG(FATAL) << "Unexpected memory barrier " << kind;
2740 }
2741 __ dmb(flavour);
2742}
2743
2744void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2745 uint32_t offset,
2746 Register out_lo,
2747 Register out_hi) {
2748 if (offset != 0) {
2749 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002750 __ add(IP, addr, ShifterOperand(out_lo));
2751 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002752 }
2753 __ ldrexd(out_lo, out_hi, addr);
2754}
2755
2756void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2757 uint32_t offset,
2758 Register value_lo,
2759 Register value_hi,
2760 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00002761 Register temp2,
2762 HInstruction* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002763 Label fail;
2764 if (offset != 0) {
2765 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002766 __ add(IP, addr, ShifterOperand(temp1));
2767 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002768 }
2769 __ Bind(&fail);
2770 // We need a load followed by store. (The address used in a STREX instruction must
2771 // be the same as the address in the most recently executed LDREX instruction.)
2772 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00002773 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002774 __ strexd(temp1, value_lo, value_hi, addr);
2775 __ cmp(temp1, ShifterOperand(0));
2776 __ b(&fail, NE);
2777}
2778
2779void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2780 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2781
Nicolas Geoffray39468442014-09-02 15:17:15 +01002782 LocationSummary* locations =
2783 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002784 locations->SetInAt(0, Location::RequiresRegister());
2785 locations->SetInAt(1, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002786
Calin Juravle34166012014-12-19 17:22:29 +00002787
Calin Juravle52c48962014-12-16 17:02:57 +00002788 Primitive::Type field_type = field_info.GetFieldType();
2789 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00002790 bool generate_volatile = field_info.IsVolatile()
2791 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002792 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002793 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00002794 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2795 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002796 locations->AddTemp(Location::RequiresRegister());
2797 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002798 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002799 // Arm encoding have some additional constraints for ldrexd/strexd:
2800 // - registers need to be consecutive
2801 // - the first register should be even but not R14.
2802 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2803 // enable Arm encoding.
2804 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2805
2806 locations->AddTemp(Location::RequiresRegister());
2807 locations->AddTemp(Location::RequiresRegister());
2808 if (field_type == Primitive::kPrimDouble) {
2809 // For doubles we need two more registers to copy the value.
2810 locations->AddTemp(Location::RegisterLocation(R2));
2811 locations->AddTemp(Location::RegisterLocation(R3));
2812 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002813 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002814}
2815
Calin Juravle52c48962014-12-16 17:02:57 +00002816void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
2817 const FieldInfo& field_info) {
2818 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2819
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002820 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002821 Register base = locations->InAt(0).AsRegister<Register>();
2822 Location value = locations->InAt(1);
2823
2824 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002825 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002826 Primitive::Type field_type = field_info.GetFieldType();
2827 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2828
2829 if (is_volatile) {
2830 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2831 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002832
2833 switch (field_type) {
2834 case Primitive::kPrimBoolean:
2835 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002836 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002837 break;
2838 }
2839
2840 case Primitive::kPrimShort:
2841 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002842 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002843 break;
2844 }
2845
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002846 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002847 case Primitive::kPrimNot: {
Calin Juravle77520bc2015-01-12 18:45:46 +00002848 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002849 break;
2850 }
2851
2852 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002853 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002854 GenerateWideAtomicStore(base, offset,
2855 value.AsRegisterPairLow<Register>(),
2856 value.AsRegisterPairHigh<Register>(),
2857 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002858 locations->GetTemp(1).AsRegister<Register>(),
2859 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002860 } else {
2861 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002862 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002863 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002864 break;
2865 }
2866
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002867 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002868 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002869 break;
2870 }
2871
2872 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002873 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002874 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002875 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
2876 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
2877
2878 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
2879
2880 GenerateWideAtomicStore(base, offset,
2881 value_reg_lo,
2882 value_reg_hi,
2883 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002884 locations->GetTemp(3).AsRegister<Register>(),
2885 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002886 } else {
2887 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002888 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002889 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002890 break;
2891 }
2892
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002893 case Primitive::kPrimVoid:
2894 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002895 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002896 }
Calin Juravle52c48962014-12-16 17:02:57 +00002897
Calin Juravle77520bc2015-01-12 18:45:46 +00002898 // Longs and doubles are handled in the switch.
2899 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
2900 codegen_->MaybeRecordImplicitNullCheck(instruction);
2901 }
2902
2903 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2904 Register temp = locations->GetTemp(0).AsRegister<Register>();
2905 Register card = locations->GetTemp(1).AsRegister<Register>();
2906 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2907 }
2908
Calin Juravle52c48962014-12-16 17:02:57 +00002909 if (is_volatile) {
2910 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2911 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002912}
2913
Calin Juravle52c48962014-12-16 17:02:57 +00002914void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2915 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002916 LocationSummary* locations =
2917 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002918 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002919
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002920 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00002921 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002922 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002923 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
2924 locations->SetOut(Location::RequiresRegister(),
2925 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
2926 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00002927 // Arm encoding have some additional constraints for ldrexd/strexd:
2928 // - registers need to be consecutive
2929 // - the first register should be even but not R14.
2930 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2931 // enable Arm encoding.
2932 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2933 locations->AddTemp(Location::RequiresRegister());
2934 locations->AddTemp(Location::RequiresRegister());
2935 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002936}
2937
Calin Juravle52c48962014-12-16 17:02:57 +00002938void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
2939 const FieldInfo& field_info) {
2940 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002941
Calin Juravle52c48962014-12-16 17:02:57 +00002942 LocationSummary* locations = instruction->GetLocations();
2943 Register base = locations->InAt(0).AsRegister<Register>();
2944 Location out = locations->Out();
2945 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002946 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002947 Primitive::Type field_type = field_info.GetFieldType();
2948 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2949
2950 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002951 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002952 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002953 break;
2954 }
2955
2956 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002957 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002958 break;
2959 }
2960
2961 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002962 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002963 break;
2964 }
2965
2966 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002967 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002968 break;
2969 }
2970
2971 case Primitive::kPrimInt:
2972 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002973 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002974 break;
2975 }
2976
2977 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002978 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002979 GenerateWideAtomicLoad(base, offset,
2980 out.AsRegisterPairLow<Register>(),
2981 out.AsRegisterPairHigh<Register>());
2982 } else {
2983 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
2984 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002985 break;
2986 }
2987
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002988 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002989 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002990 break;
2991 }
2992
2993 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002994 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002995 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002996 Register lo = locations->GetTemp(0).AsRegister<Register>();
2997 Register hi = locations->GetTemp(1).AsRegister<Register>();
2998 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00002999 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003000 __ vmovdrr(out_reg, lo, hi);
3001 } else {
3002 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003003 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003004 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003005 break;
3006 }
3007
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003008 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003009 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003010 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003011 }
Calin Juravle52c48962014-12-16 17:02:57 +00003012
Calin Juravle77520bc2015-01-12 18:45:46 +00003013 // Doubles are handled in the switch.
3014 if (field_type != Primitive::kPrimDouble) {
3015 codegen_->MaybeRecordImplicitNullCheck(instruction);
3016 }
3017
Calin Juravle52c48962014-12-16 17:02:57 +00003018 if (is_volatile) {
3019 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3020 }
3021}
3022
3023void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3024 HandleFieldSet(instruction, instruction->GetFieldInfo());
3025}
3026
3027void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3028 HandleFieldSet(instruction, instruction->GetFieldInfo());
3029}
3030
3031void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3032 HandleFieldGet(instruction, instruction->GetFieldInfo());
3033}
3034
3035void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3036 HandleFieldGet(instruction, instruction->GetFieldInfo());
3037}
3038
3039void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3040 HandleFieldGet(instruction, instruction->GetFieldInfo());
3041}
3042
3043void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3044 HandleFieldGet(instruction, instruction->GetFieldInfo());
3045}
3046
3047void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3048 HandleFieldSet(instruction, instruction->GetFieldInfo());
3049}
3050
3051void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3052 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003053}
3054
3055void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003056 LocationSummary* locations =
3057 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003058 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003059 if (instruction->HasUses()) {
3060 locations->SetOut(Location::SameAsFirstInput());
3061 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003062}
3063
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003064void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003065 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3066 return;
3067 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003068 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003069
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003070 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3071 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3072}
3073
3074void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003075 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003076 codegen_->AddSlowPath(slow_path);
3077
3078 LocationSummary* locations = instruction->GetLocations();
3079 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003080
Calin Juravle77520bc2015-01-12 18:45:46 +00003081 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
3082 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003083}
3084
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003085void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3086 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3087 GenerateImplicitNullCheck(instruction);
3088 } else {
3089 GenerateExplicitNullCheck(instruction);
3090 }
3091}
3092
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003093void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003094 LocationSummary* locations =
3095 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003096 locations->SetInAt(0, Location::RequiresRegister());
3097 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3098 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003099}
3100
3101void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3102 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003103 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003104 Location index = locations->InAt(1);
3105
3106 switch (instruction->GetType()) {
3107 case Primitive::kPrimBoolean: {
3108 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003109 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003110 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003111 size_t offset =
3112 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003113 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3114 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003115 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003116 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3117 }
3118 break;
3119 }
3120
3121 case Primitive::kPrimByte: {
3122 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003123 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003124 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003125 size_t offset =
3126 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003127 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3128 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003129 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003130 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3131 }
3132 break;
3133 }
3134
3135 case Primitive::kPrimShort: {
3136 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003137 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003138 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003139 size_t offset =
3140 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003141 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3142 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003143 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003144 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3145 }
3146 break;
3147 }
3148
3149 case Primitive::kPrimChar: {
3150 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003151 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003152 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003153 size_t offset =
3154 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003155 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3156 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003157 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003158 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3159 }
3160 break;
3161 }
3162
3163 case Primitive::kPrimInt:
3164 case Primitive::kPrimNot: {
3165 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3166 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003167 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003168 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003169 size_t offset =
3170 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003171 __ LoadFromOffset(kLoadWord, out, obj, offset);
3172 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003173 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003174 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3175 }
3176 break;
3177 }
3178
3179 case Primitive::kPrimLong: {
3180 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003181 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003182 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003183 size_t offset =
3184 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003185 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003186 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003187 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003188 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003189 }
3190 break;
3191 }
3192
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003193 case Primitive::kPrimFloat: {
3194 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3195 Location out = locations->Out();
3196 DCHECK(out.IsFpuRegister());
3197 if (index.IsConstant()) {
3198 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3199 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3200 } else {
3201 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3202 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3203 }
3204 break;
3205 }
3206
3207 case Primitive::kPrimDouble: {
3208 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3209 Location out = locations->Out();
3210 DCHECK(out.IsFpuRegisterPair());
3211 if (index.IsConstant()) {
3212 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3213 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3214 } else {
3215 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3216 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3217 }
3218 break;
3219 }
3220
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003221 case Primitive::kPrimVoid:
3222 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003223 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003224 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003225 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003226}
3227
3228void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003229 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003230
3231 bool needs_write_barrier =
3232 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3233 bool needs_runtime_call = instruction->NeedsTypeCheck();
3234
Nicolas Geoffray39468442014-09-02 15:17:15 +01003235 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003236 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3237 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003238 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003239 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3240 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3241 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003242 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003243 locations->SetInAt(0, Location::RequiresRegister());
3244 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3245 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003246
3247 if (needs_write_barrier) {
3248 // Temporary registers for the write barrier.
3249 locations->AddTemp(Location::RequiresRegister());
3250 locations->AddTemp(Location::RequiresRegister());
3251 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003252 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003253}
3254
3255void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3256 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003257 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003258 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003259 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003260 bool needs_runtime_call = locations->WillCall();
3261 bool needs_write_barrier =
3262 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003263
3264 switch (value_type) {
3265 case Primitive::kPrimBoolean:
3266 case Primitive::kPrimByte: {
3267 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003268 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003269 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003270 size_t offset =
3271 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003272 __ StoreToOffset(kStoreByte, value, obj, offset);
3273 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003274 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003275 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3276 }
3277 break;
3278 }
3279
3280 case Primitive::kPrimShort:
3281 case Primitive::kPrimChar: {
3282 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003283 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003284 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003285 size_t offset =
3286 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003287 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3288 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003289 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003290 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3291 }
3292 break;
3293 }
3294
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003295 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003296 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003297 if (!needs_runtime_call) {
3298 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003299 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003300 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003301 size_t offset =
3302 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003303 __ StoreToOffset(kStoreWord, value, obj, offset);
3304 } else {
3305 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003306 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003307 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3308 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003309 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003310 if (needs_write_barrier) {
3311 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003312 Register temp = locations->GetTemp(0).AsRegister<Register>();
3313 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003314 codegen_->MarkGCCard(temp, card, obj, value);
3315 }
3316 } else {
3317 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003318 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3319 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003320 instruction->GetDexPc(),
3321 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003322 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003323 break;
3324 }
3325
3326 case Primitive::kPrimLong: {
3327 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003328 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003329 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003330 size_t offset =
3331 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003332 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003333 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003334 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003335 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003336 }
3337 break;
3338 }
3339
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003340 case Primitive::kPrimFloat: {
3341 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3342 Location value = locations->InAt(2);
3343 DCHECK(value.IsFpuRegister());
3344 if (index.IsConstant()) {
3345 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3346 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3347 } else {
3348 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3349 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3350 }
3351 break;
3352 }
3353
3354 case Primitive::kPrimDouble: {
3355 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3356 Location value = locations->InAt(2);
3357 DCHECK(value.IsFpuRegisterPair());
3358 if (index.IsConstant()) {
3359 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3360 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3361 } else {
3362 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3363 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3364 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003365
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003366 break;
3367 }
3368
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003369 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003370 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003371 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003372 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003373
3374 // Ints and objects are handled in the switch.
3375 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3376 codegen_->MaybeRecordImplicitNullCheck(instruction);
3377 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003378}
3379
3380void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003381 LocationSummary* locations =
3382 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003383 locations->SetInAt(0, Location::RequiresRegister());
3384 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003385}
3386
3387void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3388 LocationSummary* locations = instruction->GetLocations();
3389 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003390 Register obj = locations->InAt(0).AsRegister<Register>();
3391 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003392 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003393 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003394}
3395
3396void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003397 LocationSummary* locations =
3398 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003399 locations->SetInAt(0, Location::RequiresRegister());
3400 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003401 if (instruction->HasUses()) {
3402 locations->SetOut(Location::SameAsFirstInput());
3403 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003404}
3405
3406void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3407 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003408 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003409 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003410 codegen_->AddSlowPath(slow_path);
3411
Roland Levillain271ab9c2014-11-27 15:23:57 +00003412 Register index = locations->InAt(0).AsRegister<Register>();
3413 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003414
3415 __ cmp(index, ShifterOperand(length));
3416 __ b(slow_path->GetEntryLabel(), CS);
3417}
3418
3419void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
3420 Label is_null;
3421 __ CompareAndBranchIfZero(value, &is_null);
3422 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3423 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3424 __ strb(card, Address(card, temp));
3425 __ Bind(&is_null);
3426}
3427
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003428void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3429 temp->SetLocations(nullptr);
3430}
3431
3432void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3433 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003434 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003435}
3436
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003437void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003438 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003439 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003440}
3441
3442void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003443 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3444}
3445
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003446void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3447 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3448}
3449
3450void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003451 HBasicBlock* block = instruction->GetBlock();
3452 if (block->GetLoopInformation() != nullptr) {
3453 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3454 // The back edge will generate the suspend check.
3455 return;
3456 }
3457 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3458 // The goto will generate the suspend check.
3459 return;
3460 }
3461 GenerateSuspendCheck(instruction, nullptr);
3462}
3463
3464void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3465 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003466 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003467 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003468 codegen_->AddSlowPath(slow_path);
3469
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003470 __ LoadFromOffset(
3471 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3472 __ cmp(IP, ShifterOperand(0));
3473 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003474 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003475 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003476 __ Bind(slow_path->GetReturnLabel());
3477 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003478 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003479 __ b(slow_path->GetEntryLabel());
3480 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003481}
3482
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003483ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3484 return codegen_->GetAssembler();
3485}
3486
3487void ParallelMoveResolverARM::EmitMove(size_t index) {
3488 MoveOperands* move = moves_.Get(index);
3489 Location source = move->GetSource();
3490 Location destination = move->GetDestination();
3491
3492 if (source.IsRegister()) {
3493 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003494 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003495 } else {
3496 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003497 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003498 SP, destination.GetStackIndex());
3499 }
3500 } else if (source.IsStackSlot()) {
3501 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003502 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003503 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003504 } else if (destination.IsFpuRegister()) {
3505 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003506 } else {
3507 DCHECK(destination.IsStackSlot());
3508 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3509 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3510 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003511 } else if (source.IsFpuRegister()) {
3512 if (destination.IsFpuRegister()) {
3513 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003514 } else {
3515 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003516 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3517 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003518 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003519 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003520 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
3521 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003522 } else if (destination.IsRegisterPair()) {
3523 DCHECK(ExpectedPairLayout(destination));
3524 __ LoadFromOffset(
3525 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
3526 } else {
3527 DCHECK(destination.IsFpuRegisterPair()) << destination;
3528 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3529 SP,
3530 source.GetStackIndex());
3531 }
3532 } else if (source.IsRegisterPair()) {
3533 if (destination.IsRegisterPair()) {
3534 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
3535 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
3536 } else {
3537 DCHECK(destination.IsDoubleStackSlot()) << destination;
3538 DCHECK(ExpectedPairLayout(source));
3539 __ StoreToOffset(
3540 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
3541 }
3542 } else if (source.IsFpuRegisterPair()) {
3543 if (destination.IsFpuRegisterPair()) {
3544 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3545 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
3546 } else {
3547 DCHECK(destination.IsDoubleStackSlot()) << destination;
3548 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
3549 SP,
3550 destination.GetStackIndex());
3551 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003552 } else {
3553 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003554 HConstant* constant = source.GetConstant();
3555 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3556 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003557 if (destination.IsRegister()) {
3558 __ LoadImmediate(destination.AsRegister<Register>(), value);
3559 } else {
3560 DCHECK(destination.IsStackSlot());
3561 __ LoadImmediate(IP, value);
3562 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3563 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003564 } else if (constant->IsLongConstant()) {
3565 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003566 if (destination.IsRegisterPair()) {
3567 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
3568 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003569 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003570 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003571 __ LoadImmediate(IP, Low32Bits(value));
3572 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3573 __ LoadImmediate(IP, High32Bits(value));
3574 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3575 }
3576 } else if (constant->IsDoubleConstant()) {
3577 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003578 if (destination.IsFpuRegisterPair()) {
3579 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003580 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003581 DCHECK(destination.IsDoubleStackSlot()) << destination;
3582 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003583 __ LoadImmediate(IP, Low32Bits(int_value));
3584 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3585 __ LoadImmediate(IP, High32Bits(int_value));
3586 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3587 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003588 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003589 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003590 float value = constant->AsFloatConstant()->GetValue();
3591 if (destination.IsFpuRegister()) {
3592 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3593 } else {
3594 DCHECK(destination.IsStackSlot());
3595 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3596 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3597 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003598 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003599 }
3600}
3601
3602void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3603 __ Mov(IP, reg);
3604 __ LoadFromOffset(kLoadWord, reg, SP, mem);
3605 __ StoreToOffset(kStoreWord, IP, SP, mem);
3606}
3607
3608void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3609 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3610 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3611 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3612 SP, mem1 + stack_offset);
3613 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3614 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3615 SP, mem2 + stack_offset);
3616 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3617}
3618
3619void ParallelMoveResolverARM::EmitSwap(size_t index) {
3620 MoveOperands* move = moves_.Get(index);
3621 Location source = move->GetSource();
3622 Location destination = move->GetDestination();
3623
3624 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003625 DCHECK_NE(source.AsRegister<Register>(), IP);
3626 DCHECK_NE(destination.AsRegister<Register>(), IP);
3627 __ Mov(IP, source.AsRegister<Register>());
3628 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3629 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003630 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003631 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003632 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003633 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003634 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3635 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003636 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003637 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003638 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003639 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003640 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003641 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003642 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003643 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003644 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
3645 destination.AsRegisterPairHigh<Register>(),
3646 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003647 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003648 Register low_reg = source.IsRegisterPair()
3649 ? source.AsRegisterPairLow<Register>()
3650 : destination.AsRegisterPairLow<Register>();
3651 int mem = source.IsRegisterPair()
3652 ? destination.GetStackIndex()
3653 : source.GetStackIndex();
3654 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003655 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003656 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003657 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003658 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003659 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
3660 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003661 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003662 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003663 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003664 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
3665 DRegister reg = source.IsFpuRegisterPair()
3666 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
3667 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3668 int mem = source.IsFpuRegisterPair()
3669 ? destination.GetStackIndex()
3670 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003671 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003672 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003673 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003674 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3675 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3676 : destination.AsFpuRegister<SRegister>();
3677 int mem = source.IsFpuRegister()
3678 ? destination.GetStackIndex()
3679 : source.GetStackIndex();
3680
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003681 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003682 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003683 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003684 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003685 Exchange(source.GetStackIndex(), destination.GetStackIndex());
3686 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003687 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003688 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003689 }
3690}
3691
3692void ParallelMoveResolverARM::SpillScratch(int reg) {
3693 __ Push(static_cast<Register>(reg));
3694}
3695
3696void ParallelMoveResolverARM::RestoreScratch(int reg) {
3697 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003698}
3699
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003700void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003701 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3702 ? LocationSummary::kCallOnSlowPath
3703 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003704 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003705 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003706 locations->SetOut(Location::RequiresRegister());
3707}
3708
3709void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003710 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003711 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003712 DCHECK(!cls->CanCallRuntime());
3713 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003714 codegen_->LoadCurrentMethod(out);
3715 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3716 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003717 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003718 codegen_->LoadCurrentMethod(out);
3719 __ LoadFromOffset(
3720 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
3721 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003722
3723 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3724 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3725 codegen_->AddSlowPath(slow_path);
3726 __ cmp(out, ShifterOperand(0));
3727 __ b(slow_path->GetEntryLabel(), EQ);
3728 if (cls->MustGenerateClinitCheck()) {
3729 GenerateClassInitializationCheck(slow_path, out);
3730 } else {
3731 __ Bind(slow_path->GetExitLabel());
3732 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003733 }
3734}
3735
3736void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3737 LocationSummary* locations =
3738 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3739 locations->SetInAt(0, Location::RequiresRegister());
3740 if (check->HasUses()) {
3741 locations->SetOut(Location::SameAsFirstInput());
3742 }
3743}
3744
3745void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003746 // We assume the class is not null.
3747 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3748 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003749 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003750 GenerateClassInitializationCheck(slow_path,
3751 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003752}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003753
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003754void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3755 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003756 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3757 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3758 __ b(slow_path->GetEntryLabel(), LT);
3759 // Even if the initialized flag is set, we may be in a situation where caches are not synced
3760 // properly. Therefore, we do a memory fence.
3761 __ dmb(ISH);
3762 __ Bind(slow_path->GetExitLabel());
3763}
3764
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003765void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3766 LocationSummary* locations =
3767 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3768 locations->SetOut(Location::RequiresRegister());
3769}
3770
3771void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
3772 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
3773 codegen_->AddSlowPath(slow_path);
3774
Roland Levillain271ab9c2014-11-27 15:23:57 +00003775 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003776 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003777 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3778 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003779 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
3780 __ cmp(out, ShifterOperand(0));
3781 __ b(slow_path->GetEntryLabel(), EQ);
3782 __ Bind(slow_path->GetExitLabel());
3783}
3784
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003785void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
3786 LocationSummary* locations =
3787 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3788 locations->SetOut(Location::RequiresRegister());
3789}
3790
3791void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003792 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003793 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
3794 __ LoadFromOffset(kLoadWord, out, TR, offset);
3795 __ LoadImmediate(IP, 0);
3796 __ StoreToOffset(kStoreWord, IP, TR, offset);
3797}
3798
3799void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
3800 LocationSummary* locations =
3801 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3802 InvokeRuntimeCallingConvention calling_convention;
3803 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3804}
3805
3806void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
3807 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003808 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003809}
3810
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003811void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003812 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3813 ? LocationSummary::kNoCall
3814 : LocationSummary::kCallOnSlowPath;
3815 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3816 locations->SetInAt(0, Location::RequiresRegister());
3817 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003818 // The out register is used as a temporary, so it overlaps with the inputs.
3819 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003820}
3821
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003822void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003823 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003824 Register obj = locations->InAt(0).AsRegister<Register>();
3825 Register cls = locations->InAt(1).AsRegister<Register>();
3826 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003827 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3828 Label done, zero;
3829 SlowPathCodeARM* slow_path = nullptr;
3830
3831 // Return 0 if `obj` is null.
3832 // TODO: avoid this check if we know obj is not null.
3833 __ cmp(obj, ShifterOperand(0));
3834 __ b(&zero, EQ);
3835 // Compare the class of `obj` with `cls`.
3836 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
3837 __ cmp(out, ShifterOperand(cls));
3838 if (instruction->IsClassFinal()) {
3839 // Classes must be equal for the instanceof to succeed.
3840 __ b(&zero, NE);
3841 __ LoadImmediate(out, 1);
3842 __ b(&done);
3843 } else {
3844 // If the classes are not equal, we go into a slow path.
3845 DCHECK(locations->OnlyCallsOnSlowPath());
3846 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003847 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003848 codegen_->AddSlowPath(slow_path);
3849 __ b(slow_path->GetEntryLabel(), NE);
3850 __ LoadImmediate(out, 1);
3851 __ b(&done);
3852 }
3853 __ Bind(&zero);
3854 __ LoadImmediate(out, 0);
3855 if (slow_path != nullptr) {
3856 __ Bind(slow_path->GetExitLabel());
3857 }
3858 __ Bind(&done);
3859}
3860
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003861void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
3862 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3863 instruction, LocationSummary::kCallOnSlowPath);
3864 locations->SetInAt(0, Location::RequiresRegister());
3865 locations->SetInAt(1, Location::RequiresRegister());
3866 locations->AddTemp(Location::RequiresRegister());
3867}
3868
3869void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
3870 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003871 Register obj = locations->InAt(0).AsRegister<Register>();
3872 Register cls = locations->InAt(1).AsRegister<Register>();
3873 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003874 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3875
3876 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3877 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3878 codegen_->AddSlowPath(slow_path);
3879
3880 // TODO: avoid this check if we know obj is not null.
3881 __ cmp(obj, ShifterOperand(0));
3882 __ b(slow_path->GetExitLabel(), EQ);
3883 // Compare the class of `obj` with `cls`.
3884 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
3885 __ cmp(temp, ShifterOperand(cls));
3886 __ b(slow_path->GetEntryLabel(), NE);
3887 __ Bind(slow_path->GetExitLabel());
3888}
3889
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003890void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3891 LocationSummary* locations =
3892 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3893 InvokeRuntimeCallingConvention calling_convention;
3894 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3895}
3896
3897void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3898 codegen_->InvokeRuntime(instruction->IsEnter()
3899 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
3900 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003901 instruction->GetDexPc(),
3902 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003903}
3904
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003905void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3906void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3907void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3908
3909void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3910 LocationSummary* locations =
3911 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3912 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3913 || instruction->GetResultType() == Primitive::kPrimLong);
3914 locations->SetInAt(0, Location::RequiresRegister());
3915 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003916 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003917}
3918
3919void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
3920 HandleBitwiseOperation(instruction);
3921}
3922
3923void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
3924 HandleBitwiseOperation(instruction);
3925}
3926
3927void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
3928 HandleBitwiseOperation(instruction);
3929}
3930
3931void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3932 LocationSummary* locations = instruction->GetLocations();
3933
3934 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003935 Register first = locations->InAt(0).AsRegister<Register>();
3936 Register second = locations->InAt(1).AsRegister<Register>();
3937 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003938 if (instruction->IsAnd()) {
3939 __ and_(out, first, ShifterOperand(second));
3940 } else if (instruction->IsOr()) {
3941 __ orr(out, first, ShifterOperand(second));
3942 } else {
3943 DCHECK(instruction->IsXor());
3944 __ eor(out, first, ShifterOperand(second));
3945 }
3946 } else {
3947 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3948 Location first = locations->InAt(0);
3949 Location second = locations->InAt(1);
3950 Location out = locations->Out();
3951 if (instruction->IsAnd()) {
3952 __ and_(out.AsRegisterPairLow<Register>(),
3953 first.AsRegisterPairLow<Register>(),
3954 ShifterOperand(second.AsRegisterPairLow<Register>()));
3955 __ and_(out.AsRegisterPairHigh<Register>(),
3956 first.AsRegisterPairHigh<Register>(),
3957 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3958 } else if (instruction->IsOr()) {
3959 __ orr(out.AsRegisterPairLow<Register>(),
3960 first.AsRegisterPairLow<Register>(),
3961 ShifterOperand(second.AsRegisterPairLow<Register>()));
3962 __ orr(out.AsRegisterPairHigh<Register>(),
3963 first.AsRegisterPairHigh<Register>(),
3964 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3965 } else {
3966 DCHECK(instruction->IsXor());
3967 __ eor(out.AsRegisterPairLow<Register>(),
3968 first.AsRegisterPairLow<Register>(),
3969 ShifterOperand(second.AsRegisterPairLow<Register>()));
3970 __ eor(out.AsRegisterPairHigh<Register>(),
3971 first.AsRegisterPairHigh<Register>(),
3972 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3973 }
3974 }
3975}
3976
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003977void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
3978 DCHECK_EQ(temp, kArtMethodRegister);
3979
3980 // TODO: Implement all kinds of calls:
3981 // 1) boot -> boot
3982 // 2) app -> boot
3983 // 3) app -> app
3984 //
3985 // Currently we implement the app -> app logic, which looks up in the resolve cache.
3986
3987 // temp = method;
3988 LoadCurrentMethod(temp);
3989 if (!invoke->IsRecursive()) {
3990 // temp = temp->dex_cache_resolved_methods_;
3991 __ LoadFromOffset(
3992 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
3993 // temp = temp[index_in_cache]
3994 __ LoadFromOffset(
3995 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
3996 // LR = temp[offset_of_quick_compiled_code]
3997 __ LoadFromOffset(kLoadWord, LR, temp,
3998 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3999 kArmWordSize).Int32Value());
4000 // LR()
4001 __ blx(LR);
4002 } else {
4003 __ bl(GetFrameEntryLabel());
4004 }
4005
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004006 DCHECK(!IsLeafMethod());
4007}
4008
Calin Juravleb1498f62015-02-16 13:13:29 +00004009void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4010 // Nothing to do, this should be removed during prepare for register allocator.
4011 UNUSED(instruction);
4012 LOG(FATAL) << "Unreachable";
4013}
4014
4015void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4016 // Nothing to do, this should be removed during prepare for register allocator.
4017 UNUSED(instruction);
4018 LOG(FATAL) << "Unreachable";
4019}
4020
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004021} // namespace arm
4022} // namespace art