blob: a799a519c05fc25a0599a04dde4a330a58e54b8a [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
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100516static dwarf::Reg DWARFReg(Register reg) {
517 return dwarf::Reg::ArmCore(static_cast<int>(reg));
518}
519
520static dwarf::Reg DWARFReg(SRegister reg) {
521 return dwarf::Reg::ArmFp(static_cast<int>(reg));
522}
523
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000524void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000525 bool skip_overflow_check =
526 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000527 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000528 __ Bind(&frame_entry_label_);
529
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000530 if (HasEmptyFrame()) {
531 return;
532 }
533
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100534 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000535 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
536 __ LoadFromOffset(kLoadWord, IP, IP, 0);
537 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100538 }
539
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000540 // PC is in the list of callee-save to mimic Quick, but we need to push
541 // LR at entry instead.
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100542 uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR;
543 __ PushList(push_mask);
544 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask));
545 __ cfi().RelOffsetForMany(DWARFReg(Register(0)), 0, push_mask, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000546 if (fpu_spill_mask_ != 0) {
547 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
548 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100549 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
550 __ cfi().RelOffsetForMany(DWARFReg(SRegister(0)), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000551 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100552 int adjust = GetFrameSize() - FrameEntrySpillSize();
553 __ AddConstant(SP, -adjust);
554 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100555 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000556}
557
558void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000559 if (HasEmptyFrame()) {
560 __ bx(LR);
561 return;
562 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100563 int adjust = GetFrameSize() - FrameEntrySpillSize();
564 __ AddConstant(SP, adjust);
565 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000566 if (fpu_spill_mask_ != 0) {
567 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
568 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100569 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
570 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000571 }
572 __ PopList(core_spill_mask_);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000573}
574
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100575void CodeGeneratorARM::Bind(HBasicBlock* block) {
576 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000577}
578
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100579Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
580 switch (load->GetType()) {
581 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100582 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100583 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100584
585 case Primitive::kPrimInt:
586 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100587 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100589
590 case Primitive::kPrimBoolean:
591 case Primitive::kPrimByte:
592 case Primitive::kPrimChar:
593 case Primitive::kPrimShort:
594 case Primitive::kPrimVoid:
595 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700596 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100597 }
598
599 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700600 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100601}
602
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100603Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
604 switch (type) {
605 case Primitive::kPrimBoolean:
606 case Primitive::kPrimByte:
607 case Primitive::kPrimChar:
608 case Primitive::kPrimShort:
609 case Primitive::kPrimInt:
610 case Primitive::kPrimNot: {
611 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000612 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100613 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100614 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100615 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000616 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100617 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100618 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100619
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000620 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100621 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000622 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100623 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000624 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100625 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000626 if (calling_convention.GetRegisterAt(index) == R1) {
627 // Skip R1, and use R2_R3 instead.
628 gp_index_++;
629 index++;
630 }
631 }
632 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
633 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000634 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000635 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000636 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100637 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000638 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
639 }
640 }
641
642 case Primitive::kPrimFloat: {
643 uint32_t stack_index = stack_index_++;
644 if (float_index_ % 2 == 0) {
645 float_index_ = std::max(double_index_, float_index_);
646 }
647 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
648 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
649 } else {
650 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
651 }
652 }
653
654 case Primitive::kPrimDouble: {
655 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
656 uint32_t stack_index = stack_index_;
657 stack_index_ += 2;
658 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
659 uint32_t index = double_index_;
660 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000661 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000662 calling_convention.GetFpuRegisterAt(index),
663 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000664 DCHECK(ExpectedPairLayout(result));
665 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000666 } else {
667 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100668 }
669 }
670
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100671 case Primitive::kPrimVoid:
672 LOG(FATAL) << "Unexpected parameter type " << type;
673 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100674 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100675 return Location();
676}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100677
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000678Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
679 switch (type) {
680 case Primitive::kPrimBoolean:
681 case Primitive::kPrimByte:
682 case Primitive::kPrimChar:
683 case Primitive::kPrimShort:
684 case Primitive::kPrimInt:
685 case Primitive::kPrimNot: {
686 return Location::RegisterLocation(R0);
687 }
688
689 case Primitive::kPrimFloat: {
690 return Location::FpuRegisterLocation(S0);
691 }
692
693 case Primitive::kPrimLong: {
694 return Location::RegisterPairLocation(R0, R1);
695 }
696
697 case Primitive::kPrimDouble: {
698 return Location::FpuRegisterPairLocation(S0, S1);
699 }
700
701 case Primitive::kPrimVoid:
702 return Location();
703 }
704 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000705}
706
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100707void CodeGeneratorARM::Move32(Location destination, Location source) {
708 if (source.Equals(destination)) {
709 return;
710 }
711 if (destination.IsRegister()) {
712 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000713 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100714 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000715 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100716 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000717 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100718 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100719 } else if (destination.IsFpuRegister()) {
720 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000721 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100722 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000723 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100724 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000725 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100726 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100727 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000728 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100729 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000730 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100731 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000732 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100733 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000734 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100735 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
736 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100737 }
738 }
739}
740
741void CodeGeneratorARM::Move64(Location destination, Location source) {
742 if (source.Equals(destination)) {
743 return;
744 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100745 if (destination.IsRegisterPair()) {
746 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000747 EmitParallelMoves(
748 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
749 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
750 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
751 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100752 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000753 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100754 } else {
755 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000756 DCHECK(ExpectedPairLayout(destination));
757 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
758 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100759 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000760 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100761 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000762 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
763 SP,
764 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100765 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000766 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100767 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100768 } else {
769 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100770 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000771 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100772 if (source.AsRegisterPairLow<Register>() == R1) {
773 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100774 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
775 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100776 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100777 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100778 SP, destination.GetStackIndex());
779 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000780 } else if (source.IsFpuRegisterPair()) {
781 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
782 SP,
783 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100784 } else {
785 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000786 EmitParallelMoves(
787 Location::StackSlot(source.GetStackIndex()),
788 Location::StackSlot(destination.GetStackIndex()),
789 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
790 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100791 }
792 }
793}
794
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100795void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100796 LocationSummary* locations = instruction->GetLocations();
797 if (locations != nullptr && locations->Out().Equals(location)) {
798 return;
799 }
800
Calin Juravlea21f5982014-11-13 15:53:04 +0000801 if (locations != nullptr && locations->Out().IsConstant()) {
802 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000803 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
804 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000805 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000806 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000807 } else {
808 DCHECK(location.IsStackSlot());
809 __ LoadImmediate(IP, value);
810 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
811 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000812 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000813 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000814 int64_t value = const_to_move->AsLongConstant()->GetValue();
815 if (location.IsRegisterPair()) {
816 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
817 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
818 } else {
819 DCHECK(location.IsDoubleStackSlot());
820 __ LoadImmediate(IP, Low32Bits(value));
821 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
822 __ LoadImmediate(IP, High32Bits(value));
823 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
824 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100825 }
Roland Levillain476df552014-10-09 17:51:36 +0100826 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100827 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
828 switch (instruction->GetType()) {
829 case Primitive::kPrimBoolean:
830 case Primitive::kPrimByte:
831 case Primitive::kPrimChar:
832 case Primitive::kPrimShort:
833 case Primitive::kPrimInt:
834 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100835 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100836 Move32(location, Location::StackSlot(stack_slot));
837 break;
838
839 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100840 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100841 Move64(location, Location::DoubleStackSlot(stack_slot));
842 break;
843
844 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100845 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100846 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000847 } else if (instruction->IsTemporary()) {
848 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000849 if (temp_location.IsStackSlot()) {
850 Move32(location, temp_location);
851 } else {
852 DCHECK(temp_location.IsDoubleStackSlot());
853 Move64(location, temp_location);
854 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000855 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100856 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100857 switch (instruction->GetType()) {
858 case Primitive::kPrimBoolean:
859 case Primitive::kPrimByte:
860 case Primitive::kPrimChar:
861 case Primitive::kPrimShort:
862 case Primitive::kPrimNot:
863 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100864 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100865 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100866 break;
867
868 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100869 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100870 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100871 break;
872
873 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100874 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100875 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000876 }
877}
878
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100879void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
880 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000881 uint32_t dex_pc,
882 SlowPathCode* slow_path) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100883 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
884 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000885 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100886 DCHECK(instruction->IsSuspendCheck()
887 || instruction->IsBoundsCheck()
888 || instruction->IsNullCheck()
Calin Juravled0d48522014-11-04 16:40:20 +0000889 || instruction->IsDivZeroCheck()
Roland Levillain624279f2014-12-04 11:54:28 +0000890 || instruction->GetLocations()->CanCall()
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100891 || !IsLeafMethod());
892}
893
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000894void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000895 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000896}
897
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000898void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000899 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100900 DCHECK(!successor->IsExitBlock());
901
902 HBasicBlock* block = got->GetBlock();
903 HInstruction* previous = got->GetPrevious();
904
905 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000906 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100907 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
908 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
909 return;
910 }
911
912 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
913 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
914 }
915 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000916 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000917 }
918}
919
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000920void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000921 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000922}
923
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000924void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700925 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000926}
927
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700928void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
929 Label* true_target,
930 Label* false_target,
931 Label* always_true_target) {
932 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100933 if (cond->IsIntConstant()) {
934 // Constant condition, statically compared against 1.
935 int32_t cond_value = cond->AsIntConstant()->GetValue();
936 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700937 if (always_true_target != nullptr) {
938 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100939 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100940 return;
941 } else {
942 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100943 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100944 } else {
945 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
946 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700947 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
948 __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100949 ShifterOperand(0));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700950 __ b(true_target, NE);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100951 } else {
952 // Condition has not been materialized, use its inputs as the
953 // comparison and its condition as the branch condition.
954 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000955 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000956 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100957 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000958 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100959 } else {
960 DCHECK(locations->InAt(1).IsConstant());
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000961 HConstant* constant = locations->InAt(1).GetConstant();
962 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100963 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000964 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
965 __ cmp(left, operand);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100966 } else {
967 Register temp = IP;
968 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000969 __ cmp(left, ShifterOperand(temp));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100970 }
971 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700972 __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100973 }
Dave Allison20dfc792014-06-16 20:44:29 -0700974 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700975 if (false_target != nullptr) {
976 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000977 }
978}
979
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700980void LocationsBuilderARM::VisitIf(HIf* if_instr) {
981 LocationSummary* locations =
982 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
983 HInstruction* cond = if_instr->InputAt(0);
984 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
985 locations->SetInAt(0, Location::RequiresRegister());
986 }
987}
988
989void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
990 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
991 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
992 Label* always_true_target = true_target;
993 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
994 if_instr->IfTrueSuccessor())) {
995 always_true_target = nullptr;
996 }
997 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
998 if_instr->IfFalseSuccessor())) {
999 false_target = nullptr;
1000 }
1001 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1002}
1003
1004void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1005 LocationSummary* locations = new (GetGraph()->GetArena())
1006 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1007 HInstruction* cond = deoptimize->InputAt(0);
1008 DCHECK(cond->IsCondition());
1009 if (cond->AsCondition()->NeedsMaterialization()) {
1010 locations->SetInAt(0, Location::RequiresRegister());
1011 }
1012}
1013
1014void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1015 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
1016 DeoptimizationSlowPathARM(deoptimize);
1017 codegen_->AddSlowPath(slow_path);
1018 Label* slow_path_entry = slow_path->GetEntryLabel();
1019 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1020}
Dave Allison20dfc792014-06-16 20:44:29 -07001021
1022void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001023 LocationSummary* locations =
1024 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001025 locations->SetInAt(0, Location::RequiresRegister());
1026 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001027 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001028 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001029 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001030}
1031
Dave Allison20dfc792014-06-16 20:44:29 -07001032void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001033 if (!comp->NeedsMaterialization()) return;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001034 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001035 Register left = locations->InAt(0).AsRegister<Register>();
1036
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001037 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001038 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001039 } else {
1040 DCHECK(locations->InAt(1).IsConstant());
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001041 int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001042 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001043 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
1044 __ cmp(left, operand);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001045 } else {
1046 Register temp = IP;
1047 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001048 __ cmp(left, ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001049 }
Dave Allison20dfc792014-06-16 20:44:29 -07001050 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001051 __ it(ARMCondition(comp->GetCondition()), kItElse);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001052 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001053 ARMCondition(comp->GetCondition()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001054 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001055 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -07001056}
1057
1058void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1059 VisitCondition(comp);
1060}
1061
1062void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1063 VisitCondition(comp);
1064}
1065
1066void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1067 VisitCondition(comp);
1068}
1069
1070void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1071 VisitCondition(comp);
1072}
1073
1074void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1075 VisitCondition(comp);
1076}
1077
1078void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1079 VisitCondition(comp);
1080}
1081
1082void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1083 VisitCondition(comp);
1084}
1085
1086void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1087 VisitCondition(comp);
1088}
1089
1090void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1091 VisitCondition(comp);
1092}
1093
1094void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1095 VisitCondition(comp);
1096}
1097
1098void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1099 VisitCondition(comp);
1100}
1101
1102void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1103 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001104}
1105
1106void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001107 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001108}
1109
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001110void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1111 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001112}
1113
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001114void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001115 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001116}
1117
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001118void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001119 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001120 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001121}
1122
1123void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001124 LocationSummary* locations =
1125 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001126 switch (store->InputAt(1)->GetType()) {
1127 case Primitive::kPrimBoolean:
1128 case Primitive::kPrimByte:
1129 case Primitive::kPrimChar:
1130 case Primitive::kPrimShort:
1131 case Primitive::kPrimInt:
1132 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001133 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001134 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1135 break;
1136
1137 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001138 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001139 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1140 break;
1141
1142 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001143 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001144 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001145}
1146
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001147void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001148 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001149}
1150
1151void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001152 LocationSummary* locations =
1153 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001154 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001155}
1156
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001157void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001158 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001159 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001160}
1161
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001162void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1163 LocationSummary* locations =
1164 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1165 locations->SetOut(Location::ConstantLocation(constant));
1166}
1167
1168void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1169 // Will be generated at use site.
1170 UNUSED(constant);
1171}
1172
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001173void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001174 LocationSummary* locations =
1175 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001176 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001177}
1178
1179void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1180 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001181 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001182}
1183
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001184void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1185 LocationSummary* locations =
1186 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1187 locations->SetOut(Location::ConstantLocation(constant));
1188}
1189
1190void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1191 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001192 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001193}
1194
1195void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1196 LocationSummary* locations =
1197 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1198 locations->SetOut(Location::ConstantLocation(constant));
1199}
1200
1201void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1202 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001203 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001204}
1205
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001206void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001207 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001208}
1209
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001210void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001211 UNUSED(ret);
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001212 __ cfi().RememberState();
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001213 codegen_->GenerateFrameExit();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001214 __ cfi().RestoreState();
1215 __ cfi().DefCFAOffset(codegen_->GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001216}
1217
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001218void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001219 LocationSummary* locations =
1220 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001221 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001222}
1223
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001224void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001225 UNUSED(ret);
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001226 __ cfi().RememberState();
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001227 codegen_->GenerateFrameExit();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01001228 __ cfi().RestoreState();
1229 __ cfi().DefCFAOffset(codegen_->GetFrameSize());
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001230}
1231
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001232void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001233 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1234 codegen_->GetInstructionSetFeatures());
1235 if (intrinsic.TryDispatch(invoke)) {
1236 return;
1237 }
1238
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001239 HandleInvoke(invoke);
1240}
1241
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001242void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001243 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001244 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001245}
1246
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001247static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1248 if (invoke->GetLocations()->Intrinsified()) {
1249 IntrinsicCodeGeneratorARM intrinsic(codegen);
1250 intrinsic.Dispatch(invoke);
1251 return true;
1252 }
1253 return false;
1254}
1255
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001256void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001257 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1258 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001259 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001260
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001261 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1262
1263 codegen_->GenerateStaticOrDirectCall(invoke, temp);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001264 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001265}
1266
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001267void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001268 LocationSummary* locations =
1269 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001270 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001271
1272 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001273 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001274 HInstruction* input = invoke->InputAt(i);
1275 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1276 }
1277
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001278 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001279}
1280
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001281void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001282 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1283 codegen_->GetInstructionSetFeatures());
1284 if (intrinsic.TryDispatch(invoke)) {
1285 return;
1286 }
1287
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001288 HandleInvoke(invoke);
1289}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001290
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001291void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001292 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1293 return;
1294 }
1295
Roland Levillain271ab9c2014-11-27 15:23:57 +00001296 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001297 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1298 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1299 LocationSummary* locations = invoke->GetLocations();
1300 Location receiver = locations->InAt(0);
1301 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1302 // temp = object->GetClass();
1303 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001304 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1305 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001306 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001307 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001308 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001309 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001310 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001311 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001312 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001313 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001314 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001315 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001316 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001317 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001318 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001319 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001320}
1321
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001322void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1323 HandleInvoke(invoke);
1324 // Add the hidden argument.
1325 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1326}
1327
1328void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1329 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001330 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001331 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1332 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1333 LocationSummary* locations = invoke->GetLocations();
1334 Location receiver = locations->InAt(0);
1335 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1336
1337 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001338 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1339 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001340
1341 // temp = object->GetClass();
1342 if (receiver.IsStackSlot()) {
1343 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1344 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1345 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001346 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001347 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001348 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001349 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001350 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001351 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001352 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1353 // LR = temp->GetEntryPoint();
1354 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1355 // LR();
1356 __ blx(LR);
1357 DCHECK(!codegen_->IsLeafMethod());
1358 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1359}
1360
Roland Levillain88cb1752014-10-20 16:36:47 +01001361void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1362 LocationSummary* locations =
1363 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1364 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001365 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001366 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001367 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1368 break;
1369 }
1370 case Primitive::kPrimLong: {
1371 locations->SetInAt(0, Location::RequiresRegister());
1372 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001373 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001374 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001375
Roland Levillain88cb1752014-10-20 16:36:47 +01001376 case Primitive::kPrimFloat:
1377 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001378 locations->SetInAt(0, Location::RequiresFpuRegister());
1379 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001380 break;
1381
1382 default:
1383 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1384 }
1385}
1386
1387void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1388 LocationSummary* locations = neg->GetLocations();
1389 Location out = locations->Out();
1390 Location in = locations->InAt(0);
1391 switch (neg->GetResultType()) {
1392 case Primitive::kPrimInt:
1393 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001394 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001395 break;
1396
1397 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001398 DCHECK(in.IsRegisterPair());
1399 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1400 __ rsbs(out.AsRegisterPairLow<Register>(),
1401 in.AsRegisterPairLow<Register>(),
1402 ShifterOperand(0));
1403 // We cannot emit an RSC (Reverse Subtract with Carry)
1404 // instruction here, as it does not exist in the Thumb-2
1405 // instruction set. We use the following approach
1406 // using SBC and SUB instead.
1407 //
1408 // out.hi = -C
1409 __ sbc(out.AsRegisterPairHigh<Register>(),
1410 out.AsRegisterPairHigh<Register>(),
1411 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1412 // out.hi = out.hi - in.hi
1413 __ sub(out.AsRegisterPairHigh<Register>(),
1414 out.AsRegisterPairHigh<Register>(),
1415 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1416 break;
1417
Roland Levillain88cb1752014-10-20 16:36:47 +01001418 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001419 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001420 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001421 break;
1422
Roland Levillain88cb1752014-10-20 16:36:47 +01001423 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001424 DCHECK(in.IsFpuRegisterPair());
1425 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1426 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001427 break;
1428
1429 default:
1430 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1431 }
1432}
1433
Roland Levillaindff1f282014-11-05 14:15:05 +00001434void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001435 Primitive::Type result_type = conversion->GetResultType();
1436 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001437 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001438
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001439 // The float-to-long and double-to-long type conversions rely on a
1440 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001441 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001442 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1443 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001444 ? LocationSummary::kCall
1445 : LocationSummary::kNoCall;
1446 LocationSummary* locations =
1447 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1448
David Brazdilb2bd1c52015-03-25 11:17:37 +00001449 // The Java language does not allow treating boolean as an integral type but
1450 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001451
Roland Levillaindff1f282014-11-05 14:15:05 +00001452 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001453 case Primitive::kPrimByte:
1454 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001455 case Primitive::kPrimBoolean:
1456 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001457 case Primitive::kPrimShort:
1458 case Primitive::kPrimInt:
1459 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001460 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001461 locations->SetInAt(0, Location::RequiresRegister());
1462 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1463 break;
1464
1465 default:
1466 LOG(FATAL) << "Unexpected type conversion from " << input_type
1467 << " to " << result_type;
1468 }
1469 break;
1470
Roland Levillain01a8d712014-11-14 16:27:39 +00001471 case Primitive::kPrimShort:
1472 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001473 case Primitive::kPrimBoolean:
1474 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001475 case Primitive::kPrimByte:
1476 case Primitive::kPrimInt:
1477 case Primitive::kPrimChar:
1478 // Processing a Dex `int-to-short' instruction.
1479 locations->SetInAt(0, Location::RequiresRegister());
1480 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1481 break;
1482
1483 default:
1484 LOG(FATAL) << "Unexpected type conversion from " << input_type
1485 << " to " << result_type;
1486 }
1487 break;
1488
Roland Levillain946e1432014-11-11 17:35:19 +00001489 case Primitive::kPrimInt:
1490 switch (input_type) {
1491 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001492 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001493 locations->SetInAt(0, Location::Any());
1494 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1495 break;
1496
1497 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001498 // Processing a Dex `float-to-int' instruction.
1499 locations->SetInAt(0, Location::RequiresFpuRegister());
1500 locations->SetOut(Location::RequiresRegister());
1501 locations->AddTemp(Location::RequiresFpuRegister());
1502 break;
1503
Roland Levillain946e1432014-11-11 17:35:19 +00001504 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001505 // Processing a Dex `double-to-int' instruction.
1506 locations->SetInAt(0, Location::RequiresFpuRegister());
1507 locations->SetOut(Location::RequiresRegister());
1508 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001509 break;
1510
1511 default:
1512 LOG(FATAL) << "Unexpected type conversion from " << input_type
1513 << " to " << result_type;
1514 }
1515 break;
1516
Roland Levillaindff1f282014-11-05 14:15:05 +00001517 case Primitive::kPrimLong:
1518 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001519 case Primitive::kPrimBoolean:
1520 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001521 case Primitive::kPrimByte:
1522 case Primitive::kPrimShort:
1523 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001524 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001525 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001526 locations->SetInAt(0, Location::RequiresRegister());
1527 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1528 break;
1529
Roland Levillain624279f2014-12-04 11:54:28 +00001530 case Primitive::kPrimFloat: {
1531 // Processing a Dex `float-to-long' instruction.
1532 InvokeRuntimeCallingConvention calling_convention;
1533 locations->SetInAt(0, Location::FpuRegisterLocation(
1534 calling_convention.GetFpuRegisterAt(0)));
1535 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1536 break;
1537 }
1538
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001539 case Primitive::kPrimDouble: {
1540 // Processing a Dex `double-to-long' instruction.
1541 InvokeRuntimeCallingConvention calling_convention;
1542 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1543 calling_convention.GetFpuRegisterAt(0),
1544 calling_convention.GetFpuRegisterAt(1)));
1545 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001546 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001547 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001548
1549 default:
1550 LOG(FATAL) << "Unexpected type conversion from " << input_type
1551 << " to " << result_type;
1552 }
1553 break;
1554
Roland Levillain981e4542014-11-14 11:47:14 +00001555 case Primitive::kPrimChar:
1556 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001557 case Primitive::kPrimBoolean:
1558 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001559 case Primitive::kPrimByte:
1560 case Primitive::kPrimShort:
1561 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001562 // Processing a Dex `int-to-char' instruction.
1563 locations->SetInAt(0, Location::RequiresRegister());
1564 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1565 break;
1566
1567 default:
1568 LOG(FATAL) << "Unexpected type conversion from " << input_type
1569 << " to " << result_type;
1570 }
1571 break;
1572
Roland Levillaindff1f282014-11-05 14:15:05 +00001573 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001574 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001575 case Primitive::kPrimBoolean:
1576 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001577 case Primitive::kPrimByte:
1578 case Primitive::kPrimShort:
1579 case Primitive::kPrimInt:
1580 case Primitive::kPrimChar:
1581 // Processing a Dex `int-to-float' instruction.
1582 locations->SetInAt(0, Location::RequiresRegister());
1583 locations->SetOut(Location::RequiresFpuRegister());
1584 break;
1585
1586 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001587 // Processing a Dex `long-to-float' instruction.
1588 locations->SetInAt(0, Location::RequiresRegister());
1589 locations->SetOut(Location::RequiresFpuRegister());
1590 locations->AddTemp(Location::RequiresRegister());
1591 locations->AddTemp(Location::RequiresRegister());
1592 locations->AddTemp(Location::RequiresFpuRegister());
1593 locations->AddTemp(Location::RequiresFpuRegister());
1594 break;
1595
Roland Levillaincff13742014-11-17 14:32:17 +00001596 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001597 // Processing a Dex `double-to-float' instruction.
1598 locations->SetInAt(0, Location::RequiresFpuRegister());
1599 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001600 break;
1601
1602 default:
1603 LOG(FATAL) << "Unexpected type conversion from " << input_type
1604 << " to " << result_type;
1605 };
1606 break;
1607
Roland Levillaindff1f282014-11-05 14:15:05 +00001608 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001609 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001610 case Primitive::kPrimBoolean:
1611 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001612 case Primitive::kPrimByte:
1613 case Primitive::kPrimShort:
1614 case Primitive::kPrimInt:
1615 case Primitive::kPrimChar:
1616 // Processing a Dex `int-to-double' instruction.
1617 locations->SetInAt(0, Location::RequiresRegister());
1618 locations->SetOut(Location::RequiresFpuRegister());
1619 break;
1620
1621 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001622 // Processing a Dex `long-to-double' instruction.
1623 locations->SetInAt(0, Location::RequiresRegister());
1624 locations->SetOut(Location::RequiresFpuRegister());
1625 locations->AddTemp(Location::RequiresRegister());
1626 locations->AddTemp(Location::RequiresRegister());
1627 locations->AddTemp(Location::RequiresFpuRegister());
1628 break;
1629
Roland Levillaincff13742014-11-17 14:32:17 +00001630 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001631 // Processing a Dex `float-to-double' instruction.
1632 locations->SetInAt(0, Location::RequiresFpuRegister());
1633 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001634 break;
1635
1636 default:
1637 LOG(FATAL) << "Unexpected type conversion from " << input_type
1638 << " to " << result_type;
1639 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001640 break;
1641
1642 default:
1643 LOG(FATAL) << "Unexpected type conversion from " << input_type
1644 << " to " << result_type;
1645 }
1646}
1647
1648void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1649 LocationSummary* locations = conversion->GetLocations();
1650 Location out = locations->Out();
1651 Location in = locations->InAt(0);
1652 Primitive::Type result_type = conversion->GetResultType();
1653 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001654 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001655 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001656 case Primitive::kPrimByte:
1657 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001658 case Primitive::kPrimBoolean:
1659 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001660 case Primitive::kPrimShort:
1661 case Primitive::kPrimInt:
1662 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001663 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001664 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001665 break;
1666
1667 default:
1668 LOG(FATAL) << "Unexpected type conversion from " << input_type
1669 << " to " << result_type;
1670 }
1671 break;
1672
Roland Levillain01a8d712014-11-14 16:27:39 +00001673 case Primitive::kPrimShort:
1674 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001675 case Primitive::kPrimBoolean:
1676 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001677 case Primitive::kPrimByte:
1678 case Primitive::kPrimInt:
1679 case Primitive::kPrimChar:
1680 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001681 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001682 break;
1683
1684 default:
1685 LOG(FATAL) << "Unexpected type conversion from " << input_type
1686 << " to " << result_type;
1687 }
1688 break;
1689
Roland Levillain946e1432014-11-11 17:35:19 +00001690 case Primitive::kPrimInt:
1691 switch (input_type) {
1692 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001693 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001694 DCHECK(out.IsRegister());
1695 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001696 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001697 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001698 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001699 } else {
1700 DCHECK(in.IsConstant());
1701 DCHECK(in.GetConstant()->IsLongConstant());
1702 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001703 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001704 }
1705 break;
1706
Roland Levillain3f8f9362014-12-02 17:45:01 +00001707 case Primitive::kPrimFloat: {
1708 // Processing a Dex `float-to-int' instruction.
1709 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1710 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1711 __ vcvtis(temp, temp);
1712 __ vmovrs(out.AsRegister<Register>(), temp);
1713 break;
1714 }
1715
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001716 case Primitive::kPrimDouble: {
1717 // Processing a Dex `double-to-int' instruction.
1718 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1719 DRegister temp_d = FromLowSToD(temp_s);
1720 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1721 __ vcvtid(temp_s, temp_d);
1722 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001723 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001724 }
Roland Levillain946e1432014-11-11 17:35:19 +00001725
1726 default:
1727 LOG(FATAL) << "Unexpected type conversion from " << input_type
1728 << " to " << result_type;
1729 }
1730 break;
1731
Roland Levillaindff1f282014-11-05 14:15:05 +00001732 case Primitive::kPrimLong:
1733 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001734 case Primitive::kPrimBoolean:
1735 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001736 case Primitive::kPrimByte:
1737 case Primitive::kPrimShort:
1738 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001739 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001740 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001741 DCHECK(out.IsRegisterPair());
1742 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001743 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001744 // Sign extension.
1745 __ Asr(out.AsRegisterPairHigh<Register>(),
1746 out.AsRegisterPairLow<Register>(),
1747 31);
1748 break;
1749
1750 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001751 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00001752 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1753 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001754 conversion->GetDexPc(),
1755 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00001756 break;
1757
Roland Levillaindff1f282014-11-05 14:15:05 +00001758 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001759 // Processing a Dex `double-to-long' instruction.
1760 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1761 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001762 conversion->GetDexPc(),
1763 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00001764 break;
1765
1766 default:
1767 LOG(FATAL) << "Unexpected type conversion from " << input_type
1768 << " to " << result_type;
1769 }
1770 break;
1771
Roland Levillain981e4542014-11-14 11:47:14 +00001772 case Primitive::kPrimChar:
1773 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001774 case Primitive::kPrimBoolean:
1775 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001776 case Primitive::kPrimByte:
1777 case Primitive::kPrimShort:
1778 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001779 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001780 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00001781 break;
1782
1783 default:
1784 LOG(FATAL) << "Unexpected type conversion from " << input_type
1785 << " to " << result_type;
1786 }
1787 break;
1788
Roland Levillaindff1f282014-11-05 14:15:05 +00001789 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001790 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001791 case Primitive::kPrimBoolean:
1792 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001793 case Primitive::kPrimByte:
1794 case Primitive::kPrimShort:
1795 case Primitive::kPrimInt:
1796 case Primitive::kPrimChar: {
1797 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001798 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1799 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001800 break;
1801 }
1802
Roland Levillain6d0e4832014-11-27 18:31:21 +00001803 case Primitive::kPrimLong: {
1804 // Processing a Dex `long-to-float' instruction.
1805 Register low = in.AsRegisterPairLow<Register>();
1806 Register high = in.AsRegisterPairHigh<Register>();
1807 SRegister output = out.AsFpuRegister<SRegister>();
1808 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1809 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1810 SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1811 DRegister temp1_d = FromLowSToD(temp1_s);
1812 SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
1813 DRegister temp2_d = FromLowSToD(temp2_s);
1814
1815 // Operations use doubles for precision reasons (each 32-bit
1816 // half of a long fits in the 53-bit mantissa of a double,
1817 // but not in the 24-bit mantissa of a float). This is
1818 // especially important for the low bits. The result is
1819 // eventually converted to float.
1820
1821 // temp1_d = int-to-double(high)
1822 __ vmovsr(temp1_s, high);
1823 __ vcvtdi(temp1_d, temp1_s);
1824 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1825 // as an immediate value into `temp2_d` does not work, as
1826 // this instruction only transfers 8 significant bits of its
1827 // immediate operand. Instead, use two 32-bit core
1828 // registers to load `k2Pow32EncodingForDouble` into
1829 // `temp2_d`.
1830 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1831 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1832 __ vmovdrr(temp2_d, constant_low, constant_high);
1833 // temp1_d = temp1_d * 2^32
1834 __ vmuld(temp1_d, temp1_d, temp2_d);
1835 // temp2_d = unsigned-to-double(low)
1836 __ vmovsr(temp2_s, low);
1837 __ vcvtdu(temp2_d, temp2_s);
1838 // temp1_d = temp1_d + temp2_d
1839 __ vaddd(temp1_d, temp1_d, temp2_d);
1840 // output = double-to-float(temp1_d);
1841 __ vcvtsd(output, temp1_d);
1842 break;
1843 }
1844
Roland Levillaincff13742014-11-17 14:32:17 +00001845 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001846 // Processing a Dex `double-to-float' instruction.
1847 __ vcvtsd(out.AsFpuRegister<SRegister>(),
1848 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00001849 break;
1850
1851 default:
1852 LOG(FATAL) << "Unexpected type conversion from " << input_type
1853 << " to " << result_type;
1854 };
1855 break;
1856
Roland Levillaindff1f282014-11-05 14:15:05 +00001857 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001858 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001859 case Primitive::kPrimBoolean:
1860 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001861 case Primitive::kPrimByte:
1862 case Primitive::kPrimShort:
1863 case Primitive::kPrimInt:
1864 case Primitive::kPrimChar: {
1865 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001866 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001867 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1868 out.AsFpuRegisterPairLow<SRegister>());
1869 break;
1870 }
1871
Roland Levillain647b9ed2014-11-27 12:06:00 +00001872 case Primitive::kPrimLong: {
1873 // Processing a Dex `long-to-double' instruction.
1874 Register low = in.AsRegisterPairLow<Register>();
1875 Register high = in.AsRegisterPairHigh<Register>();
1876 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1877 DRegister out_d = FromLowSToD(out_s);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001878 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1879 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001880 SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1881 DRegister temp_d = FromLowSToD(temp_s);
1882
Roland Levillain647b9ed2014-11-27 12:06:00 +00001883 // out_d = int-to-double(high)
1884 __ vmovsr(out_s, high);
1885 __ vcvtdi(out_d, out_s);
Roland Levillain6d0e4832014-11-27 18:31:21 +00001886 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1887 // as an immediate value into `temp_d` does not work, as
1888 // this instruction only transfers 8 significant bits of its
1889 // immediate operand. Instead, use two 32-bit core
1890 // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
1891 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1892 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001893 __ vmovdrr(temp_d, constant_low, constant_high);
1894 // out_d = out_d * 2^32
1895 __ vmuld(out_d, out_d, temp_d);
1896 // temp_d = unsigned-to-double(low)
1897 __ vmovsr(temp_s, low);
1898 __ vcvtdu(temp_d, temp_s);
1899 // out_d = out_d + temp_d
1900 __ vaddd(out_d, out_d, temp_d);
1901 break;
1902 }
1903
Roland Levillaincff13742014-11-17 14:32:17 +00001904 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001905 // Processing a Dex `float-to-double' instruction.
1906 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1907 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001908 break;
1909
1910 default:
1911 LOG(FATAL) << "Unexpected type conversion from " << input_type
1912 << " to " << result_type;
1913 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001914 break;
1915
1916 default:
1917 LOG(FATAL) << "Unexpected type conversion from " << input_type
1918 << " to " << result_type;
1919 }
1920}
1921
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001922void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001923 LocationSummary* locations =
1924 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001925 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001926 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001927 locations->SetInAt(0, Location::RequiresRegister());
1928 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001929 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1930 break;
1931 }
1932
1933 case Primitive::kPrimLong: {
1934 locations->SetInAt(0, Location::RequiresRegister());
1935 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001936 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001937 break;
1938 }
1939
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001940 case Primitive::kPrimFloat:
1941 case Primitive::kPrimDouble: {
1942 locations->SetInAt(0, Location::RequiresFpuRegister());
1943 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001944 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001945 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001946 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001947
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001948 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001949 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001950 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001951}
1952
1953void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1954 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001955 Location out = locations->Out();
1956 Location first = locations->InAt(0);
1957 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001958 switch (add->GetResultType()) {
1959 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001960 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001961 __ add(out.AsRegister<Register>(),
1962 first.AsRegister<Register>(),
1963 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001964 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001965 __ AddConstant(out.AsRegister<Register>(),
1966 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001967 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001968 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001969 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001970
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001971 case Primitive::kPrimLong: {
1972 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001973 __ adds(out.AsRegisterPairLow<Register>(),
1974 first.AsRegisterPairLow<Register>(),
1975 ShifterOperand(second.AsRegisterPairLow<Register>()));
1976 __ adc(out.AsRegisterPairHigh<Register>(),
1977 first.AsRegisterPairHigh<Register>(),
1978 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001979 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001980 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001981
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001982 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00001983 __ vadds(out.AsFpuRegister<SRegister>(),
1984 first.AsFpuRegister<SRegister>(),
1985 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001986 break;
1987
1988 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001989 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1990 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1991 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001992 break;
1993
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001994 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001995 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001996 }
1997}
1998
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001999void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002000 LocationSummary* locations =
2001 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002002 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002003 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002004 locations->SetInAt(0, Location::RequiresRegister());
2005 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002006 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2007 break;
2008 }
2009
2010 case Primitive::kPrimLong: {
2011 locations->SetInAt(0, Location::RequiresRegister());
2012 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002013 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002014 break;
2015 }
Calin Juravle11351682014-10-23 15:38:15 +01002016 case Primitive::kPrimFloat:
2017 case Primitive::kPrimDouble: {
2018 locations->SetInAt(0, Location::RequiresFpuRegister());
2019 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002020 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002021 break;
Calin Juravle11351682014-10-23 15:38:15 +01002022 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002023 default:
Calin Juravle11351682014-10-23 15:38:15 +01002024 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002025 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002026}
2027
2028void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2029 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002030 Location out = locations->Out();
2031 Location first = locations->InAt(0);
2032 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002033 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002034 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002035 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002036 __ sub(out.AsRegister<Register>(),
2037 first.AsRegister<Register>(),
2038 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002039 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002040 __ AddConstant(out.AsRegister<Register>(),
2041 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002042 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002043 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002044 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002045 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002046
Calin Juravle11351682014-10-23 15:38:15 +01002047 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002048 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002049 __ subs(out.AsRegisterPairLow<Register>(),
2050 first.AsRegisterPairLow<Register>(),
2051 ShifterOperand(second.AsRegisterPairLow<Register>()));
2052 __ sbc(out.AsRegisterPairHigh<Register>(),
2053 first.AsRegisterPairHigh<Register>(),
2054 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002055 break;
Calin Juravle11351682014-10-23 15:38:15 +01002056 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002057
Calin Juravle11351682014-10-23 15:38:15 +01002058 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002059 __ vsubs(out.AsFpuRegister<SRegister>(),
2060 first.AsFpuRegister<SRegister>(),
2061 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002062 break;
Calin Juravle11351682014-10-23 15:38:15 +01002063 }
2064
2065 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002066 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2067 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2068 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002069 break;
2070 }
2071
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002072
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002073 default:
Calin Juravle11351682014-10-23 15:38:15 +01002074 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002075 }
2076}
2077
Calin Juravle34bacdf2014-10-07 20:23:36 +01002078void LocationsBuilderARM::VisitMul(HMul* mul) {
2079 LocationSummary* locations =
2080 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2081 switch (mul->GetResultType()) {
2082 case Primitive::kPrimInt:
2083 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002084 locations->SetInAt(0, Location::RequiresRegister());
2085 locations->SetInAt(1, Location::RequiresRegister());
2086 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002087 break;
2088 }
2089
Calin Juravleb5bfa962014-10-21 18:02:24 +01002090 case Primitive::kPrimFloat:
2091 case Primitive::kPrimDouble: {
2092 locations->SetInAt(0, Location::RequiresFpuRegister());
2093 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002094 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002095 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002096 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002097
2098 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002099 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002100 }
2101}
2102
2103void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2104 LocationSummary* locations = mul->GetLocations();
2105 Location out = locations->Out();
2106 Location first = locations->InAt(0);
2107 Location second = locations->InAt(1);
2108 switch (mul->GetResultType()) {
2109 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002110 __ mul(out.AsRegister<Register>(),
2111 first.AsRegister<Register>(),
2112 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002113 break;
2114 }
2115 case Primitive::kPrimLong: {
2116 Register out_hi = out.AsRegisterPairHigh<Register>();
2117 Register out_lo = out.AsRegisterPairLow<Register>();
2118 Register in1_hi = first.AsRegisterPairHigh<Register>();
2119 Register in1_lo = first.AsRegisterPairLow<Register>();
2120 Register in2_hi = second.AsRegisterPairHigh<Register>();
2121 Register in2_lo = second.AsRegisterPairLow<Register>();
2122
2123 // Extra checks to protect caused by the existence of R1_R2.
2124 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2125 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2126 DCHECK_NE(out_hi, in1_lo);
2127 DCHECK_NE(out_hi, in2_lo);
2128
2129 // input: in1 - 64 bits, in2 - 64 bits
2130 // output: out
2131 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2132 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2133 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2134
2135 // IP <- in1.lo * in2.hi
2136 __ mul(IP, in1_lo, in2_hi);
2137 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2138 __ mla(out_hi, in1_hi, in2_lo, IP);
2139 // out.lo <- (in1.lo * in2.lo)[31:0];
2140 __ umull(out_lo, IP, in1_lo, in2_lo);
2141 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2142 __ add(out_hi, out_hi, ShifterOperand(IP));
2143 break;
2144 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002145
2146 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002147 __ vmuls(out.AsFpuRegister<SRegister>(),
2148 first.AsFpuRegister<SRegister>(),
2149 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002150 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002151 }
2152
2153 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002154 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2155 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2156 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002157 break;
2158 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002159
2160 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002161 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002162 }
2163}
2164
Calin Juravle7c4954d2014-10-28 16:57:40 +00002165void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002166 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2167 if (div->GetResultType() == Primitive::kPrimLong) {
2168 // pLdiv runtime call.
2169 call_kind = LocationSummary::kCall;
2170 } else if (div->GetResultType() == Primitive::kPrimInt &&
2171 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2172 // pIdivmod runtime call.
2173 call_kind = LocationSummary::kCall;
2174 }
2175
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002176 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2177
Calin Juravle7c4954d2014-10-28 16:57:40 +00002178 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002179 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002180 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2181 locations->SetInAt(0, Location::RequiresRegister());
2182 locations->SetInAt(1, Location::RequiresRegister());
2183 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2184 } else {
2185 InvokeRuntimeCallingConvention calling_convention;
2186 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2187 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2188 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2189 // we only need the former.
2190 locations->SetOut(Location::RegisterLocation(R0));
2191 }
Calin Juravled0d48522014-11-04 16:40:20 +00002192 break;
2193 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002194 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002195 InvokeRuntimeCallingConvention calling_convention;
2196 locations->SetInAt(0, Location::RegisterPairLocation(
2197 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2198 locations->SetInAt(1, Location::RegisterPairLocation(
2199 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002200 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002201 break;
2202 }
2203 case Primitive::kPrimFloat:
2204 case Primitive::kPrimDouble: {
2205 locations->SetInAt(0, Location::RequiresFpuRegister());
2206 locations->SetInAt(1, Location::RequiresFpuRegister());
2207 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2208 break;
2209 }
2210
2211 default:
2212 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2213 }
2214}
2215
2216void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2217 LocationSummary* locations = div->GetLocations();
2218 Location out = locations->Out();
2219 Location first = locations->InAt(0);
2220 Location second = locations->InAt(1);
2221
2222 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002223 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002224 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2225 __ sdiv(out.AsRegister<Register>(),
2226 first.AsRegister<Register>(),
2227 second.AsRegister<Register>());
2228 } else {
2229 InvokeRuntimeCallingConvention calling_convention;
2230 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2231 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2232 DCHECK_EQ(R0, out.AsRegister<Register>());
2233
2234 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2235 }
Calin Juravled0d48522014-11-04 16:40:20 +00002236 break;
2237 }
2238
Calin Juravle7c4954d2014-10-28 16:57:40 +00002239 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002240 InvokeRuntimeCallingConvention calling_convention;
2241 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2242 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2243 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2244 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2245 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002246 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002247
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002248 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002249 break;
2250 }
2251
2252 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002253 __ vdivs(out.AsFpuRegister<SRegister>(),
2254 first.AsFpuRegister<SRegister>(),
2255 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002256 break;
2257 }
2258
2259 case Primitive::kPrimDouble: {
2260 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2261 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2262 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2263 break;
2264 }
2265
2266 default:
2267 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2268 }
2269}
2270
Calin Juravlebacfec32014-11-14 15:54:36 +00002271void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002272 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002273
2274 // Most remainders are implemented in the runtime.
2275 LocationSummary::CallKind call_kind = LocationSummary::kCall;
2276 if (rem->GetResultType() == Primitive::kPrimInt &&
2277 codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2278 // Have hardware divide instruction for int, do it with three instructions.
2279 call_kind = LocationSummary::kNoCall;
2280 }
2281
Calin Juravlebacfec32014-11-14 15:54:36 +00002282 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2283
Calin Juravled2ec87d2014-12-08 14:24:46 +00002284 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002285 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002286 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2287 locations->SetInAt(0, Location::RequiresRegister());
2288 locations->SetInAt(1, Location::RequiresRegister());
2289 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2290 locations->AddTemp(Location::RequiresRegister());
2291 } else {
2292 InvokeRuntimeCallingConvention calling_convention;
2293 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2294 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2295 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2296 // we only need the latter.
2297 locations->SetOut(Location::RegisterLocation(R1));
2298 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002299 break;
2300 }
2301 case Primitive::kPrimLong: {
2302 InvokeRuntimeCallingConvention calling_convention;
2303 locations->SetInAt(0, Location::RegisterPairLocation(
2304 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2305 locations->SetInAt(1, Location::RegisterPairLocation(
2306 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2307 // The runtime helper puts the output in R2,R3.
2308 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2309 break;
2310 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002311 case Primitive::kPrimFloat: {
2312 InvokeRuntimeCallingConvention calling_convention;
2313 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2314 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2315 locations->SetOut(Location::FpuRegisterLocation(S0));
2316 break;
2317 }
2318
Calin Juravlebacfec32014-11-14 15:54:36 +00002319 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002320 InvokeRuntimeCallingConvention calling_convention;
2321 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2322 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2323 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2324 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2325 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002326 break;
2327 }
2328
2329 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002330 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002331 }
2332}
2333
2334void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2335 LocationSummary* locations = rem->GetLocations();
2336 Location out = locations->Out();
2337 Location first = locations->InAt(0);
2338 Location second = locations->InAt(1);
2339
Calin Juravled2ec87d2014-12-08 14:24:46 +00002340 Primitive::Type type = rem->GetResultType();
2341 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002342 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002343 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2344 Register reg1 = first.AsRegister<Register>();
2345 Register reg2 = second.AsRegister<Register>();
2346 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002347
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002348 // temp = reg1 / reg2 (integer division)
2349 // temp = temp * reg2
2350 // dest = reg1 - temp
2351 __ sdiv(temp, reg1, reg2);
2352 __ mul(temp, temp, reg2);
2353 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2354 } else {
2355 InvokeRuntimeCallingConvention calling_convention;
2356 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2357 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2358 DCHECK_EQ(R1, out.AsRegister<Register>());
2359
2360 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2361 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002362 break;
2363 }
2364
2365 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002366 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002367 break;
2368 }
2369
Calin Juravled2ec87d2014-12-08 14:24:46 +00002370 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002371 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002372 break;
2373 }
2374
Calin Juravlebacfec32014-11-14 15:54:36 +00002375 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002376 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002377 break;
2378 }
2379
2380 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002381 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002382 }
2383}
2384
Calin Juravled0d48522014-11-04 16:40:20 +00002385void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2386 LocationSummary* locations =
2387 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002388 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002389 if (instruction->HasUses()) {
2390 locations->SetOut(Location::SameAsFirstInput());
2391 }
2392}
2393
2394void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2395 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2396 codegen_->AddSlowPath(slow_path);
2397
2398 LocationSummary* locations = instruction->GetLocations();
2399 Location value = locations->InAt(0);
2400
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002401 switch (instruction->GetType()) {
2402 case Primitive::kPrimInt: {
2403 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002404 __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002405 __ b(slow_path->GetEntryLabel(), EQ);
2406 } else {
2407 DCHECK(value.IsConstant()) << value;
2408 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2409 __ b(slow_path->GetEntryLabel());
2410 }
2411 }
2412 break;
2413 }
2414 case Primitive::kPrimLong: {
2415 if (value.IsRegisterPair()) {
2416 __ orrs(IP,
2417 value.AsRegisterPairLow<Register>(),
2418 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2419 __ b(slow_path->GetEntryLabel(), EQ);
2420 } else {
2421 DCHECK(value.IsConstant()) << value;
2422 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2423 __ b(slow_path->GetEntryLabel());
2424 }
2425 }
2426 break;
2427 default:
2428 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2429 }
2430 }
Calin Juravled0d48522014-11-04 16:40:20 +00002431}
2432
Calin Juravle9aec02f2014-11-18 23:06:35 +00002433void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2434 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2435
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002436 LocationSummary* locations =
2437 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002438
2439 switch (op->GetResultType()) {
2440 case Primitive::kPrimInt: {
2441 locations->SetInAt(0, Location::RequiresRegister());
2442 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002443 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002444 break;
2445 }
2446 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002447 locations->SetInAt(0, Location::RequiresRegister());
2448 locations->SetInAt(1, Location::RequiresRegister());
2449 locations->AddTemp(Location::RequiresRegister());
2450 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002451 break;
2452 }
2453 default:
2454 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2455 }
2456}
2457
2458void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2459 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2460
2461 LocationSummary* locations = op->GetLocations();
2462 Location out = locations->Out();
2463 Location first = locations->InAt(0);
2464 Location second = locations->InAt(1);
2465
2466 Primitive::Type type = op->GetResultType();
2467 switch (type) {
2468 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002469 Register out_reg = out.AsRegister<Register>();
2470 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002471 // Arm doesn't mask the shift count so we need to do it ourselves.
2472 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002473 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002474 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2475 if (op->IsShl()) {
2476 __ Lsl(out_reg, first_reg, second_reg);
2477 } else if (op->IsShr()) {
2478 __ Asr(out_reg, first_reg, second_reg);
2479 } else {
2480 __ Lsr(out_reg, first_reg, second_reg);
2481 }
2482 } else {
2483 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2484 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2485 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2486 __ Mov(out_reg, first_reg);
2487 } else if (op->IsShl()) {
2488 __ Lsl(out_reg, first_reg, shift_value);
2489 } else if (op->IsShr()) {
2490 __ Asr(out_reg, first_reg, shift_value);
2491 } else {
2492 __ Lsr(out_reg, first_reg, shift_value);
2493 }
2494 }
2495 break;
2496 }
2497 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002498 Register o_h = out.AsRegisterPairHigh<Register>();
2499 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002500
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002501 Register temp = locations->GetTemp(0).AsRegister<Register>();
2502
2503 Register high = first.AsRegisterPairHigh<Register>();
2504 Register low = first.AsRegisterPairLow<Register>();
2505
2506 Register second_reg = second.AsRegister<Register>();
2507
Calin Juravle9aec02f2014-11-18 23:06:35 +00002508 if (op->IsShl()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002509 // Shift the high part
2510 __ and_(second_reg, second_reg, ShifterOperand(63));
2511 __ Lsl(o_h, high, second_reg);
2512 // Shift the low part and `or` what overflew on the high part
2513 __ rsb(temp, second_reg, ShifterOperand(32));
2514 __ Lsr(temp, low, temp);
2515 __ orr(o_h, o_h, ShifterOperand(temp));
2516 // If the shift is > 32 bits, override the high part
2517 __ subs(temp, second_reg, ShifterOperand(32));
2518 __ it(PL);
2519 __ Lsl(o_h, low, temp, false, PL);
2520 // Shift the low part
2521 __ Lsl(o_l, low, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002522 } else if (op->IsShr()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002523 // Shift the low part
2524 __ and_(second_reg, second_reg, ShifterOperand(63));
2525 __ Lsr(o_l, low, second_reg);
2526 // Shift the high part and `or` what underflew on the low part
2527 __ rsb(temp, second_reg, ShifterOperand(32));
2528 __ Lsl(temp, high, temp);
2529 __ orr(o_l, o_l, ShifterOperand(temp));
2530 // If the shift is > 32 bits, override the low part
2531 __ subs(temp, second_reg, ShifterOperand(32));
2532 __ it(PL);
2533 __ Asr(o_l, high, temp, false, PL);
2534 // Shift the high part
2535 __ Asr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002536 } else {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002537 // same as Shr except we use `Lsr`s and not `Asr`s
2538 __ and_(second_reg, second_reg, ShifterOperand(63));
2539 __ Lsr(o_l, low, second_reg);
2540 __ rsb(temp, second_reg, ShifterOperand(32));
2541 __ Lsl(temp, high, temp);
2542 __ orr(o_l, o_l, ShifterOperand(temp));
2543 __ subs(temp, second_reg, ShifterOperand(32));
2544 __ it(PL);
2545 __ Lsr(o_l, high, temp, false, PL);
2546 __ Lsr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002547 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002548 break;
2549 }
2550 default:
2551 LOG(FATAL) << "Unexpected operation type " << type;
2552 }
2553}
2554
2555void LocationsBuilderARM::VisitShl(HShl* shl) {
2556 HandleShift(shl);
2557}
2558
2559void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2560 HandleShift(shl);
2561}
2562
2563void LocationsBuilderARM::VisitShr(HShr* shr) {
2564 HandleShift(shr);
2565}
2566
2567void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2568 HandleShift(shr);
2569}
2570
2571void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2572 HandleShift(ushr);
2573}
2574
2575void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2576 HandleShift(ushr);
2577}
2578
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002579void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002580 LocationSummary* locations =
2581 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002582 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002583 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2584 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2585 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002586}
2587
2588void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2589 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002590 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002591 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002592 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2593 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002594 instruction->GetDexPc(),
2595 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002596}
2597
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002598void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2599 LocationSummary* locations =
2600 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2601 InvokeRuntimeCallingConvention calling_convention;
2602 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002603 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002604 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002605 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002606}
2607
2608void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2609 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002610 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002611 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002612 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2613 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002614 instruction->GetDexPc(),
2615 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002616}
2617
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002618void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002619 LocationSummary* locations =
2620 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002621 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2622 if (location.IsStackSlot()) {
2623 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2624 } else if (location.IsDoubleStackSlot()) {
2625 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002626 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002627 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002628}
2629
2630void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002631 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002632 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002633}
2634
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002635void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002636 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002637 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002638 locations->SetInAt(0, Location::RequiresRegister());
2639 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002640}
2641
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002642void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2643 LocationSummary* locations = not_->GetLocations();
2644 Location out = locations->Out();
2645 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002646 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002647 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002648 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002649 break;
2650
2651 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002652 __ mvn(out.AsRegisterPairLow<Register>(),
2653 ShifterOperand(in.AsRegisterPairLow<Register>()));
2654 __ mvn(out.AsRegisterPairHigh<Register>(),
2655 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002656 break;
2657
2658 default:
2659 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2660 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002661}
2662
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002663void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002664 LocationSummary* locations =
2665 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002666 switch (compare->InputAt(0)->GetType()) {
2667 case Primitive::kPrimLong: {
2668 locations->SetInAt(0, Location::RequiresRegister());
2669 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002670 // Output overlaps because it is written before doing the low comparison.
2671 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00002672 break;
2673 }
2674 case Primitive::kPrimFloat:
2675 case Primitive::kPrimDouble: {
2676 locations->SetInAt(0, Location::RequiresFpuRegister());
2677 locations->SetInAt(1, Location::RequiresFpuRegister());
2678 locations->SetOut(Location::RequiresRegister());
2679 break;
2680 }
2681 default:
2682 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2683 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002684}
2685
2686void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002687 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002688 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002689 Location left = locations->InAt(0);
2690 Location right = locations->InAt(1);
2691
2692 Label less, greater, done;
2693 Primitive::Type type = compare->InputAt(0)->GetType();
2694 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002695 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002696 __ cmp(left.AsRegisterPairHigh<Register>(),
2697 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002698 __ b(&less, LT);
2699 __ b(&greater, GT);
Calin Juravleddb7df22014-11-25 20:56:51 +00002700 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2701 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002702 __ cmp(left.AsRegisterPairLow<Register>(),
2703 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00002704 break;
2705 }
2706 case Primitive::kPrimFloat:
2707 case Primitive::kPrimDouble: {
2708 __ LoadImmediate(out, 0);
2709 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002710 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002711 } else {
2712 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2713 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2714 }
2715 __ vmstat(); // transfer FP status register to ARM APSR.
2716 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002717 break;
2718 }
2719 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002720 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002721 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002722 __ b(&done, EQ);
2723 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats.
2724
2725 __ Bind(&greater);
2726 __ LoadImmediate(out, 1);
2727 __ b(&done);
2728
2729 __ Bind(&less);
2730 __ LoadImmediate(out, -1);
2731
2732 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002733}
2734
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002735void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002736 LocationSummary* locations =
2737 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002738 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2739 locations->SetInAt(i, Location::Any());
2740 }
2741 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002742}
2743
2744void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002745 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002746 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002747}
2748
Calin Juravle52c48962014-12-16 17:02:57 +00002749void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2750 // TODO (ported from quick): revisit Arm barrier kinds
2751 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings
2752 switch (kind) {
2753 case MemBarrierKind::kAnyStore:
2754 case MemBarrierKind::kLoadAny:
2755 case MemBarrierKind::kAnyAny: {
2756 flavour = DmbOptions::ISH;
2757 break;
2758 }
2759 case MemBarrierKind::kStoreStore: {
2760 flavour = DmbOptions::ISHST;
2761 break;
2762 }
2763 default:
2764 LOG(FATAL) << "Unexpected memory barrier " << kind;
2765 }
2766 __ dmb(flavour);
2767}
2768
2769void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2770 uint32_t offset,
2771 Register out_lo,
2772 Register out_hi) {
2773 if (offset != 0) {
2774 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002775 __ add(IP, addr, ShifterOperand(out_lo));
2776 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002777 }
2778 __ ldrexd(out_lo, out_hi, addr);
2779}
2780
2781void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2782 uint32_t offset,
2783 Register value_lo,
2784 Register value_hi,
2785 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00002786 Register temp2,
2787 HInstruction* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002788 Label fail;
2789 if (offset != 0) {
2790 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002791 __ add(IP, addr, ShifterOperand(temp1));
2792 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002793 }
2794 __ Bind(&fail);
2795 // We need a load followed by store. (The address used in a STREX instruction must
2796 // be the same as the address in the most recently executed LDREX instruction.)
2797 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00002798 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002799 __ strexd(temp1, value_lo, value_hi, addr);
2800 __ cmp(temp1, ShifterOperand(0));
2801 __ b(&fail, NE);
2802}
2803
2804void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2805 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2806
Nicolas Geoffray39468442014-09-02 15:17:15 +01002807 LocationSummary* locations =
2808 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002809 locations->SetInAt(0, Location::RequiresRegister());
2810 locations->SetInAt(1, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002811
Calin Juravle34166012014-12-19 17:22:29 +00002812
Calin Juravle52c48962014-12-16 17:02:57 +00002813 Primitive::Type field_type = field_info.GetFieldType();
2814 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00002815 bool generate_volatile = field_info.IsVolatile()
2816 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002817 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002818 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00002819 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2820 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002821 locations->AddTemp(Location::RequiresRegister());
2822 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002823 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002824 // Arm encoding have some additional constraints for ldrexd/strexd:
2825 // - registers need to be consecutive
2826 // - the first register should be even but not R14.
2827 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2828 // enable Arm encoding.
2829 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2830
2831 locations->AddTemp(Location::RequiresRegister());
2832 locations->AddTemp(Location::RequiresRegister());
2833 if (field_type == Primitive::kPrimDouble) {
2834 // For doubles we need two more registers to copy the value.
2835 locations->AddTemp(Location::RegisterLocation(R2));
2836 locations->AddTemp(Location::RegisterLocation(R3));
2837 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002838 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002839}
2840
Calin Juravle52c48962014-12-16 17:02:57 +00002841void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
2842 const FieldInfo& field_info) {
2843 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2844
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002845 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002846 Register base = locations->InAt(0).AsRegister<Register>();
2847 Location value = locations->InAt(1);
2848
2849 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002850 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002851 Primitive::Type field_type = field_info.GetFieldType();
2852 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2853
2854 if (is_volatile) {
2855 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2856 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002857
2858 switch (field_type) {
2859 case Primitive::kPrimBoolean:
2860 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002861 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002862 break;
2863 }
2864
2865 case Primitive::kPrimShort:
2866 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002867 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002868 break;
2869 }
2870
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002871 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002872 case Primitive::kPrimNot: {
Calin Juravle77520bc2015-01-12 18:45:46 +00002873 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002874 break;
2875 }
2876
2877 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002878 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002879 GenerateWideAtomicStore(base, offset,
2880 value.AsRegisterPairLow<Register>(),
2881 value.AsRegisterPairHigh<Register>(),
2882 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002883 locations->GetTemp(1).AsRegister<Register>(),
2884 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002885 } else {
2886 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002887 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002888 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002889 break;
2890 }
2891
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002892 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002893 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002894 break;
2895 }
2896
2897 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002898 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002899 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002900 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
2901 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
2902
2903 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
2904
2905 GenerateWideAtomicStore(base, offset,
2906 value_reg_lo,
2907 value_reg_hi,
2908 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002909 locations->GetTemp(3).AsRegister<Register>(),
2910 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002911 } else {
2912 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002913 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002914 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002915 break;
2916 }
2917
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002918 case Primitive::kPrimVoid:
2919 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002920 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002921 }
Calin Juravle52c48962014-12-16 17:02:57 +00002922
Calin Juravle77520bc2015-01-12 18:45:46 +00002923 // Longs and doubles are handled in the switch.
2924 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
2925 codegen_->MaybeRecordImplicitNullCheck(instruction);
2926 }
2927
2928 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2929 Register temp = locations->GetTemp(0).AsRegister<Register>();
2930 Register card = locations->GetTemp(1).AsRegister<Register>();
2931 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2932 }
2933
Calin Juravle52c48962014-12-16 17:02:57 +00002934 if (is_volatile) {
2935 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2936 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002937}
2938
Calin Juravle52c48962014-12-16 17:02:57 +00002939void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2940 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002941 LocationSummary* locations =
2942 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002943 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002944
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002945 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00002946 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002947 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002948 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
2949 locations->SetOut(Location::RequiresRegister(),
2950 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
2951 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00002952 // Arm encoding have some additional constraints for ldrexd/strexd:
2953 // - registers need to be consecutive
2954 // - the first register should be even but not R14.
2955 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2956 // enable Arm encoding.
2957 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2958 locations->AddTemp(Location::RequiresRegister());
2959 locations->AddTemp(Location::RequiresRegister());
2960 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002961}
2962
Calin Juravle52c48962014-12-16 17:02:57 +00002963void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
2964 const FieldInfo& field_info) {
2965 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002966
Calin Juravle52c48962014-12-16 17:02:57 +00002967 LocationSummary* locations = instruction->GetLocations();
2968 Register base = locations->InAt(0).AsRegister<Register>();
2969 Location out = locations->Out();
2970 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002971 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002972 Primitive::Type field_type = field_info.GetFieldType();
2973 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2974
2975 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002976 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002977 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002978 break;
2979 }
2980
2981 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002982 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002983 break;
2984 }
2985
2986 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002987 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002988 break;
2989 }
2990
2991 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002992 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002993 break;
2994 }
2995
2996 case Primitive::kPrimInt:
2997 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002998 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002999 break;
3000 }
3001
3002 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003003 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003004 GenerateWideAtomicLoad(base, offset,
3005 out.AsRegisterPairLow<Register>(),
3006 out.AsRegisterPairHigh<Register>());
3007 } else {
3008 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3009 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003010 break;
3011 }
3012
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003013 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003014 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003015 break;
3016 }
3017
3018 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003019 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003020 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003021 Register lo = locations->GetTemp(0).AsRegister<Register>();
3022 Register hi = locations->GetTemp(1).AsRegister<Register>();
3023 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003024 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003025 __ vmovdrr(out_reg, lo, hi);
3026 } else {
3027 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003028 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003029 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003030 break;
3031 }
3032
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003033 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003034 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003035 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003036 }
Calin Juravle52c48962014-12-16 17:02:57 +00003037
Calin Juravle77520bc2015-01-12 18:45:46 +00003038 // Doubles are handled in the switch.
3039 if (field_type != Primitive::kPrimDouble) {
3040 codegen_->MaybeRecordImplicitNullCheck(instruction);
3041 }
3042
Calin Juravle52c48962014-12-16 17:02:57 +00003043 if (is_volatile) {
3044 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3045 }
3046}
3047
3048void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3049 HandleFieldSet(instruction, instruction->GetFieldInfo());
3050}
3051
3052void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3053 HandleFieldSet(instruction, instruction->GetFieldInfo());
3054}
3055
3056void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3057 HandleFieldGet(instruction, instruction->GetFieldInfo());
3058}
3059
3060void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3061 HandleFieldGet(instruction, instruction->GetFieldInfo());
3062}
3063
3064void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3065 HandleFieldGet(instruction, instruction->GetFieldInfo());
3066}
3067
3068void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3069 HandleFieldGet(instruction, instruction->GetFieldInfo());
3070}
3071
3072void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3073 HandleFieldSet(instruction, instruction->GetFieldInfo());
3074}
3075
3076void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3077 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003078}
3079
3080void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003081 LocationSummary* locations =
3082 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003083 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003084 if (instruction->HasUses()) {
3085 locations->SetOut(Location::SameAsFirstInput());
3086 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003087}
3088
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003089void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003090 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3091 return;
3092 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003093 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003094
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003095 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3096 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3097}
3098
3099void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003100 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003101 codegen_->AddSlowPath(slow_path);
3102
3103 LocationSummary* locations = instruction->GetLocations();
3104 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003105
Calin Juravle77520bc2015-01-12 18:45:46 +00003106 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
3107 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003108}
3109
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003110void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3111 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3112 GenerateImplicitNullCheck(instruction);
3113 } else {
3114 GenerateExplicitNullCheck(instruction);
3115 }
3116}
3117
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003118void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003119 LocationSummary* locations =
3120 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003121 locations->SetInAt(0, Location::RequiresRegister());
3122 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3123 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003124}
3125
3126void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3127 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003128 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003129 Location index = locations->InAt(1);
3130
3131 switch (instruction->GetType()) {
3132 case Primitive::kPrimBoolean: {
3133 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003134 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003135 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003136 size_t offset =
3137 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003138 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3139 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003140 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003141 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3142 }
3143 break;
3144 }
3145
3146 case Primitive::kPrimByte: {
3147 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003148 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003149 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003150 size_t offset =
3151 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003152 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3153 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003154 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003155 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3156 }
3157 break;
3158 }
3159
3160 case Primitive::kPrimShort: {
3161 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003162 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003163 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003164 size_t offset =
3165 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003166 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3167 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003168 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003169 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3170 }
3171 break;
3172 }
3173
3174 case Primitive::kPrimChar: {
3175 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003176 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003177 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003178 size_t offset =
3179 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003180 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3181 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003182 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003183 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3184 }
3185 break;
3186 }
3187
3188 case Primitive::kPrimInt:
3189 case Primitive::kPrimNot: {
3190 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3191 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003192 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003193 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003194 size_t offset =
3195 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003196 __ LoadFromOffset(kLoadWord, out, obj, offset);
3197 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003198 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003199 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3200 }
3201 break;
3202 }
3203
3204 case Primitive::kPrimLong: {
3205 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003206 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003207 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003208 size_t offset =
3209 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003210 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003211 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003212 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003213 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003214 }
3215 break;
3216 }
3217
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003218 case Primitive::kPrimFloat: {
3219 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3220 Location out = locations->Out();
3221 DCHECK(out.IsFpuRegister());
3222 if (index.IsConstant()) {
3223 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3224 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3225 } else {
3226 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3227 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3228 }
3229 break;
3230 }
3231
3232 case Primitive::kPrimDouble: {
3233 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3234 Location out = locations->Out();
3235 DCHECK(out.IsFpuRegisterPair());
3236 if (index.IsConstant()) {
3237 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3238 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3239 } else {
3240 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3241 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3242 }
3243 break;
3244 }
3245
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003246 case Primitive::kPrimVoid:
3247 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003248 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003249 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003250 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003251}
3252
3253void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003254 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003255
3256 bool needs_write_barrier =
3257 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3258 bool needs_runtime_call = instruction->NeedsTypeCheck();
3259
Nicolas Geoffray39468442014-09-02 15:17:15 +01003260 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003261 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3262 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003263 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003264 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3265 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3266 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003267 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003268 locations->SetInAt(0, Location::RequiresRegister());
3269 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3270 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003271
3272 if (needs_write_barrier) {
3273 // Temporary registers for the write barrier.
3274 locations->AddTemp(Location::RequiresRegister());
3275 locations->AddTemp(Location::RequiresRegister());
3276 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003277 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003278}
3279
3280void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3281 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003282 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003283 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003284 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003285 bool needs_runtime_call = locations->WillCall();
3286 bool needs_write_barrier =
3287 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003288
3289 switch (value_type) {
3290 case Primitive::kPrimBoolean:
3291 case Primitive::kPrimByte: {
3292 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003293 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003294 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003295 size_t offset =
3296 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003297 __ StoreToOffset(kStoreByte, value, obj, offset);
3298 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003299 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003300 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3301 }
3302 break;
3303 }
3304
3305 case Primitive::kPrimShort:
3306 case Primitive::kPrimChar: {
3307 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003308 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003309 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003310 size_t offset =
3311 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003312 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3313 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003314 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003315 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3316 }
3317 break;
3318 }
3319
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003320 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003321 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003322 if (!needs_runtime_call) {
3323 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003324 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003325 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003326 size_t offset =
3327 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003328 __ StoreToOffset(kStoreWord, value, obj, offset);
3329 } else {
3330 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003331 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003332 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3333 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003334 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003335 if (needs_write_barrier) {
3336 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003337 Register temp = locations->GetTemp(0).AsRegister<Register>();
3338 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003339 codegen_->MarkGCCard(temp, card, obj, value);
3340 }
3341 } else {
3342 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003343 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3344 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003345 instruction->GetDexPc(),
3346 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003347 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003348 break;
3349 }
3350
3351 case Primitive::kPrimLong: {
3352 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003353 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003354 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003355 size_t offset =
3356 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003357 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003358 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003359 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003360 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003361 }
3362 break;
3363 }
3364
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003365 case Primitive::kPrimFloat: {
3366 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3367 Location value = locations->InAt(2);
3368 DCHECK(value.IsFpuRegister());
3369 if (index.IsConstant()) {
3370 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3371 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3372 } else {
3373 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3374 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3375 }
3376 break;
3377 }
3378
3379 case Primitive::kPrimDouble: {
3380 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3381 Location value = locations->InAt(2);
3382 DCHECK(value.IsFpuRegisterPair());
3383 if (index.IsConstant()) {
3384 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3385 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3386 } else {
3387 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3388 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3389 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003390
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003391 break;
3392 }
3393
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003394 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003395 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003396 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003397 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003398
3399 // Ints and objects are handled in the switch.
3400 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3401 codegen_->MaybeRecordImplicitNullCheck(instruction);
3402 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003403}
3404
3405void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003406 LocationSummary* locations =
3407 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003408 locations->SetInAt(0, Location::RequiresRegister());
3409 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003410}
3411
3412void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3413 LocationSummary* locations = instruction->GetLocations();
3414 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003415 Register obj = locations->InAt(0).AsRegister<Register>();
3416 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003417 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003418 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003419}
3420
3421void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003422 LocationSummary* locations =
3423 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003424 locations->SetInAt(0, Location::RequiresRegister());
3425 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003426 if (instruction->HasUses()) {
3427 locations->SetOut(Location::SameAsFirstInput());
3428 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003429}
3430
3431void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3432 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003433 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003434 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003435 codegen_->AddSlowPath(slow_path);
3436
Roland Levillain271ab9c2014-11-27 15:23:57 +00003437 Register index = locations->InAt(0).AsRegister<Register>();
3438 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003439
3440 __ cmp(index, ShifterOperand(length));
3441 __ b(slow_path->GetEntryLabel(), CS);
3442}
3443
3444void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
3445 Label is_null;
3446 __ CompareAndBranchIfZero(value, &is_null);
3447 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3448 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3449 __ strb(card, Address(card, temp));
3450 __ Bind(&is_null);
3451}
3452
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003453void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3454 temp->SetLocations(nullptr);
3455}
3456
3457void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3458 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003459 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003460}
3461
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003462void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003463 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003464 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003465}
3466
3467void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003468 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3469}
3470
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003471void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3472 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3473}
3474
3475void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003476 HBasicBlock* block = instruction->GetBlock();
3477 if (block->GetLoopInformation() != nullptr) {
3478 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3479 // The back edge will generate the suspend check.
3480 return;
3481 }
3482 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3483 // The goto will generate the suspend check.
3484 return;
3485 }
3486 GenerateSuspendCheck(instruction, nullptr);
3487}
3488
3489void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3490 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003491 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003492 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003493 codegen_->AddSlowPath(slow_path);
3494
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003495 __ LoadFromOffset(
3496 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3497 __ cmp(IP, ShifterOperand(0));
3498 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003499 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003500 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003501 __ Bind(slow_path->GetReturnLabel());
3502 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003503 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003504 __ b(slow_path->GetEntryLabel());
3505 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003506}
3507
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003508ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3509 return codegen_->GetAssembler();
3510}
3511
3512void ParallelMoveResolverARM::EmitMove(size_t index) {
3513 MoveOperands* move = moves_.Get(index);
3514 Location source = move->GetSource();
3515 Location destination = move->GetDestination();
3516
3517 if (source.IsRegister()) {
3518 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003519 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003520 } else {
3521 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003522 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003523 SP, destination.GetStackIndex());
3524 }
3525 } else if (source.IsStackSlot()) {
3526 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003527 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003528 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003529 } else if (destination.IsFpuRegister()) {
3530 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003531 } else {
3532 DCHECK(destination.IsStackSlot());
3533 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3534 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3535 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003536 } else if (source.IsFpuRegister()) {
3537 if (destination.IsFpuRegister()) {
3538 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003539 } else {
3540 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003541 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3542 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003543 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003544 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003545 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
3546 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003547 } else if (destination.IsRegisterPair()) {
3548 DCHECK(ExpectedPairLayout(destination));
3549 __ LoadFromOffset(
3550 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
3551 } else {
3552 DCHECK(destination.IsFpuRegisterPair()) << destination;
3553 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3554 SP,
3555 source.GetStackIndex());
3556 }
3557 } else if (source.IsRegisterPair()) {
3558 if (destination.IsRegisterPair()) {
3559 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
3560 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
3561 } else {
3562 DCHECK(destination.IsDoubleStackSlot()) << destination;
3563 DCHECK(ExpectedPairLayout(source));
3564 __ StoreToOffset(
3565 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
3566 }
3567 } else if (source.IsFpuRegisterPair()) {
3568 if (destination.IsFpuRegisterPair()) {
3569 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3570 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
3571 } else {
3572 DCHECK(destination.IsDoubleStackSlot()) << destination;
3573 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
3574 SP,
3575 destination.GetStackIndex());
3576 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003577 } else {
3578 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003579 HConstant* constant = source.GetConstant();
3580 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3581 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003582 if (destination.IsRegister()) {
3583 __ LoadImmediate(destination.AsRegister<Register>(), value);
3584 } else {
3585 DCHECK(destination.IsStackSlot());
3586 __ LoadImmediate(IP, value);
3587 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3588 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003589 } else if (constant->IsLongConstant()) {
3590 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003591 if (destination.IsRegisterPair()) {
3592 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
3593 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003594 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003595 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003596 __ LoadImmediate(IP, Low32Bits(value));
3597 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3598 __ LoadImmediate(IP, High32Bits(value));
3599 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3600 }
3601 } else if (constant->IsDoubleConstant()) {
3602 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003603 if (destination.IsFpuRegisterPair()) {
3604 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003605 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003606 DCHECK(destination.IsDoubleStackSlot()) << destination;
3607 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003608 __ LoadImmediate(IP, Low32Bits(int_value));
3609 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3610 __ LoadImmediate(IP, High32Bits(int_value));
3611 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3612 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003613 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003614 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003615 float value = constant->AsFloatConstant()->GetValue();
3616 if (destination.IsFpuRegister()) {
3617 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3618 } else {
3619 DCHECK(destination.IsStackSlot());
3620 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3621 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3622 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003623 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003624 }
3625}
3626
3627void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3628 __ Mov(IP, reg);
3629 __ LoadFromOffset(kLoadWord, reg, SP, mem);
3630 __ StoreToOffset(kStoreWord, IP, SP, mem);
3631}
3632
3633void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3634 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3635 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3636 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3637 SP, mem1 + stack_offset);
3638 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3639 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3640 SP, mem2 + stack_offset);
3641 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3642}
3643
3644void ParallelMoveResolverARM::EmitSwap(size_t index) {
3645 MoveOperands* move = moves_.Get(index);
3646 Location source = move->GetSource();
3647 Location destination = move->GetDestination();
3648
3649 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003650 DCHECK_NE(source.AsRegister<Register>(), IP);
3651 DCHECK_NE(destination.AsRegister<Register>(), IP);
3652 __ Mov(IP, source.AsRegister<Register>());
3653 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3654 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003655 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003656 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003657 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003658 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003659 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3660 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003661 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003662 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003663 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003664 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003665 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003666 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003667 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003668 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003669 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
3670 destination.AsRegisterPairHigh<Register>(),
3671 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003672 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003673 Register low_reg = source.IsRegisterPair()
3674 ? source.AsRegisterPairLow<Register>()
3675 : destination.AsRegisterPairLow<Register>();
3676 int mem = source.IsRegisterPair()
3677 ? destination.GetStackIndex()
3678 : source.GetStackIndex();
3679 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003680 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003681 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003682 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003683 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003684 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
3685 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003686 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003687 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003688 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003689 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
3690 DRegister reg = source.IsFpuRegisterPair()
3691 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
3692 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3693 int mem = source.IsFpuRegisterPair()
3694 ? destination.GetStackIndex()
3695 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003696 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003697 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003698 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003699 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3700 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3701 : destination.AsFpuRegister<SRegister>();
3702 int mem = source.IsFpuRegister()
3703 ? destination.GetStackIndex()
3704 : source.GetStackIndex();
3705
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003706 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003707 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003708 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003709 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003710 Exchange(source.GetStackIndex(), destination.GetStackIndex());
3711 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003712 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003713 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003714 }
3715}
3716
3717void ParallelMoveResolverARM::SpillScratch(int reg) {
3718 __ Push(static_cast<Register>(reg));
3719}
3720
3721void ParallelMoveResolverARM::RestoreScratch(int reg) {
3722 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003723}
3724
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003725void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003726 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3727 ? LocationSummary::kCallOnSlowPath
3728 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003729 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003730 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003731 locations->SetOut(Location::RequiresRegister());
3732}
3733
3734void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003735 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003736 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003737 DCHECK(!cls->CanCallRuntime());
3738 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003739 codegen_->LoadCurrentMethod(out);
3740 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3741 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003742 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003743 codegen_->LoadCurrentMethod(out);
3744 __ LoadFromOffset(
3745 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
3746 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003747
3748 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3749 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3750 codegen_->AddSlowPath(slow_path);
3751 __ cmp(out, ShifterOperand(0));
3752 __ b(slow_path->GetEntryLabel(), EQ);
3753 if (cls->MustGenerateClinitCheck()) {
3754 GenerateClassInitializationCheck(slow_path, out);
3755 } else {
3756 __ Bind(slow_path->GetExitLabel());
3757 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003758 }
3759}
3760
3761void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3762 LocationSummary* locations =
3763 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3764 locations->SetInAt(0, Location::RequiresRegister());
3765 if (check->HasUses()) {
3766 locations->SetOut(Location::SameAsFirstInput());
3767 }
3768}
3769
3770void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003771 // We assume the class is not null.
3772 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3773 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003774 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003775 GenerateClassInitializationCheck(slow_path,
3776 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003777}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003778
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003779void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3780 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003781 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3782 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3783 __ b(slow_path->GetEntryLabel(), LT);
3784 // Even if the initialized flag is set, we may be in a situation where caches are not synced
3785 // properly. Therefore, we do a memory fence.
3786 __ dmb(ISH);
3787 __ Bind(slow_path->GetExitLabel());
3788}
3789
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003790void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3791 LocationSummary* locations =
3792 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3793 locations->SetOut(Location::RequiresRegister());
3794}
3795
3796void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
3797 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
3798 codegen_->AddSlowPath(slow_path);
3799
Roland Levillain271ab9c2014-11-27 15:23:57 +00003800 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003801 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003802 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3803 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003804 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
3805 __ cmp(out, ShifterOperand(0));
3806 __ b(slow_path->GetEntryLabel(), EQ);
3807 __ Bind(slow_path->GetExitLabel());
3808}
3809
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003810void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
3811 LocationSummary* locations =
3812 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3813 locations->SetOut(Location::RequiresRegister());
3814}
3815
3816void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003817 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003818 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
3819 __ LoadFromOffset(kLoadWord, out, TR, offset);
3820 __ LoadImmediate(IP, 0);
3821 __ StoreToOffset(kStoreWord, IP, TR, offset);
3822}
3823
3824void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
3825 LocationSummary* locations =
3826 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3827 InvokeRuntimeCallingConvention calling_convention;
3828 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3829}
3830
3831void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
3832 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003833 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003834}
3835
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003836void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003837 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3838 ? LocationSummary::kNoCall
3839 : LocationSummary::kCallOnSlowPath;
3840 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3841 locations->SetInAt(0, Location::RequiresRegister());
3842 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003843 // The out register is used as a temporary, so it overlaps with the inputs.
3844 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003845}
3846
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003847void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003848 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003849 Register obj = locations->InAt(0).AsRegister<Register>();
3850 Register cls = locations->InAt(1).AsRegister<Register>();
3851 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003852 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3853 Label done, zero;
3854 SlowPathCodeARM* slow_path = nullptr;
3855
3856 // Return 0 if `obj` is null.
3857 // TODO: avoid this check if we know obj is not null.
3858 __ cmp(obj, ShifterOperand(0));
3859 __ b(&zero, EQ);
3860 // Compare the class of `obj` with `cls`.
3861 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
3862 __ cmp(out, ShifterOperand(cls));
3863 if (instruction->IsClassFinal()) {
3864 // Classes must be equal for the instanceof to succeed.
3865 __ b(&zero, NE);
3866 __ LoadImmediate(out, 1);
3867 __ b(&done);
3868 } else {
3869 // If the classes are not equal, we go into a slow path.
3870 DCHECK(locations->OnlyCallsOnSlowPath());
3871 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003872 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003873 codegen_->AddSlowPath(slow_path);
3874 __ b(slow_path->GetEntryLabel(), NE);
3875 __ LoadImmediate(out, 1);
3876 __ b(&done);
3877 }
3878 __ Bind(&zero);
3879 __ LoadImmediate(out, 0);
3880 if (slow_path != nullptr) {
3881 __ Bind(slow_path->GetExitLabel());
3882 }
3883 __ Bind(&done);
3884}
3885
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003886void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
3887 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3888 instruction, LocationSummary::kCallOnSlowPath);
3889 locations->SetInAt(0, Location::RequiresRegister());
3890 locations->SetInAt(1, Location::RequiresRegister());
3891 locations->AddTemp(Location::RequiresRegister());
3892}
3893
3894void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
3895 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003896 Register obj = locations->InAt(0).AsRegister<Register>();
3897 Register cls = locations->InAt(1).AsRegister<Register>();
3898 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003899 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3900
3901 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3902 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3903 codegen_->AddSlowPath(slow_path);
3904
3905 // TODO: avoid this check if we know obj is not null.
3906 __ cmp(obj, ShifterOperand(0));
3907 __ b(slow_path->GetExitLabel(), EQ);
3908 // Compare the class of `obj` with `cls`.
3909 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
3910 __ cmp(temp, ShifterOperand(cls));
3911 __ b(slow_path->GetEntryLabel(), NE);
3912 __ Bind(slow_path->GetExitLabel());
3913}
3914
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003915void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3916 LocationSummary* locations =
3917 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3918 InvokeRuntimeCallingConvention calling_convention;
3919 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3920}
3921
3922void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3923 codegen_->InvokeRuntime(instruction->IsEnter()
3924 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
3925 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003926 instruction->GetDexPc(),
3927 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003928}
3929
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003930void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3931void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3932void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3933
3934void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3935 LocationSummary* locations =
3936 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3937 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3938 || instruction->GetResultType() == Primitive::kPrimLong);
3939 locations->SetInAt(0, Location::RequiresRegister());
3940 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003941 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003942}
3943
3944void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
3945 HandleBitwiseOperation(instruction);
3946}
3947
3948void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
3949 HandleBitwiseOperation(instruction);
3950}
3951
3952void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
3953 HandleBitwiseOperation(instruction);
3954}
3955
3956void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3957 LocationSummary* locations = instruction->GetLocations();
3958
3959 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003960 Register first = locations->InAt(0).AsRegister<Register>();
3961 Register second = locations->InAt(1).AsRegister<Register>();
3962 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003963 if (instruction->IsAnd()) {
3964 __ and_(out, first, ShifterOperand(second));
3965 } else if (instruction->IsOr()) {
3966 __ orr(out, first, ShifterOperand(second));
3967 } else {
3968 DCHECK(instruction->IsXor());
3969 __ eor(out, first, ShifterOperand(second));
3970 }
3971 } else {
3972 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3973 Location first = locations->InAt(0);
3974 Location second = locations->InAt(1);
3975 Location out = locations->Out();
3976 if (instruction->IsAnd()) {
3977 __ and_(out.AsRegisterPairLow<Register>(),
3978 first.AsRegisterPairLow<Register>(),
3979 ShifterOperand(second.AsRegisterPairLow<Register>()));
3980 __ and_(out.AsRegisterPairHigh<Register>(),
3981 first.AsRegisterPairHigh<Register>(),
3982 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3983 } else if (instruction->IsOr()) {
3984 __ orr(out.AsRegisterPairLow<Register>(),
3985 first.AsRegisterPairLow<Register>(),
3986 ShifterOperand(second.AsRegisterPairLow<Register>()));
3987 __ orr(out.AsRegisterPairHigh<Register>(),
3988 first.AsRegisterPairHigh<Register>(),
3989 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3990 } else {
3991 DCHECK(instruction->IsXor());
3992 __ eor(out.AsRegisterPairLow<Register>(),
3993 first.AsRegisterPairLow<Register>(),
3994 ShifterOperand(second.AsRegisterPairLow<Register>()));
3995 __ eor(out.AsRegisterPairHigh<Register>(),
3996 first.AsRegisterPairHigh<Register>(),
3997 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3998 }
3999 }
4000}
4001
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004002void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
4003 DCHECK_EQ(temp, kArtMethodRegister);
4004
4005 // TODO: Implement all kinds of calls:
4006 // 1) boot -> boot
4007 // 2) app -> boot
4008 // 3) app -> app
4009 //
4010 // Currently we implement the app -> app logic, which looks up in the resolve cache.
4011
4012 // temp = method;
4013 LoadCurrentMethod(temp);
4014 if (!invoke->IsRecursive()) {
4015 // temp = temp->dex_cache_resolved_methods_;
4016 __ LoadFromOffset(
4017 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
4018 // temp = temp[index_in_cache]
4019 __ LoadFromOffset(
4020 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
4021 // LR = temp[offset_of_quick_compiled_code]
4022 __ LoadFromOffset(kLoadWord, LR, temp,
4023 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4024 kArmWordSize).Int32Value());
4025 // LR()
4026 __ blx(LR);
4027 } else {
4028 __ bl(GetFrameEntryLabel());
4029 }
4030
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004031 DCHECK(!IsLeafMethod());
4032}
4033
Calin Juravleb1498f62015-02-16 13:13:29 +00004034void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4035 // Nothing to do, this should be removed during prepare for register allocator.
4036 UNUSED(instruction);
4037 LOG(FATAL) << "Unreachable";
4038}
4039
4040void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4041 // Nothing to do, this should be removed during prepare for register allocator.
4042 UNUSED(instruction);
4043 LOG(FATAL) << "Unreachable";
4044}
4045
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004046} // namespace arm
4047} // namespace art