blob: f5e4df13909a417c22fc2cf325c279d9521a919a [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Calin Juravle34166012014-12-19 17:22:29 +000019#include "arch/arm/instruction_set_features_arm.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070020#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010021#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080022#include "intrinsics.h"
23#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070024#include "mirror/array-inl.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000025#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010026#include "mirror/class.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070027#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010028#include "utils/arm/assembler_arm.h"
29#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000030#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010031#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000032
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace arm {
36
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000037static bool ExpectedPairLayout(Location location) {
38 // We expected this for both core and fpu register pairs.
39 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
40}
41
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010042static constexpr int kCurrentMethodStackOffset = 0;
43
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000044// We unconditionally allocate R5 to ensure we can do long operations
45// with baseline.
46static constexpr Register kCoreSavedRegisterForBaseline = R5;
47static constexpr Register kCoreCalleeSaves[] =
48 { R5, R6, R7, R8, R10, R11, PC };
49static constexpr SRegister kFpuCalleeSaves[] =
50 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010051
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000052// D31 cannot be split into two S registers, and the register allocator only works on
53// S registers. Therefore there is no need to block it.
54static constexpr DRegister DTMP = D31;
55
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010057#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010058
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010059class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010061 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010062
Alexandre Rames67555f72014-11-18 10:55:16 +000063 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010064 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010066 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000067 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 }
69
70 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
73};
74
Calin Juravled0d48522014-11-04 16:40:20 +000075class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
76 public:
77 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
78
Alexandre Rames67555f72014-11-18 10:55:16 +000079 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000080 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
81 __ Bind(GetEntryLabel());
82 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000083 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +000084 }
85
86 private:
87 HDivZeroCheck* const instruction_;
88 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
89};
90
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010091class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000092 public:
Alexandre Rames67555f72014-11-18 10:55:16 +000093 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +010094 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000095
Alexandre Rames67555f72014-11-18 10:55:16 +000096 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010097 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000098 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +000099 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100100 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000101 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000102 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100103 if (successor_ == nullptr) {
104 __ b(GetReturnLabel());
105 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100106 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100107 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000108 }
109
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100110 Label* GetReturnLabel() {
111 DCHECK(successor_ == nullptr);
112 return &return_label_;
113 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000114
115 private:
116 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100117 // If not null, the block to branch to after the suspend check.
118 HBasicBlock* const successor_;
119
120 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 Label return_label_;
122
123 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
124};
125
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100126class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100128 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
129 Location index_location,
130 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100131 : instruction_(instruction),
132 index_location_(index_location),
133 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100134
Alexandre Rames67555f72014-11-18 10:55:16 +0000135 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100136 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100137 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000138 // We're moving two locations to locations that could overlap, so we need a parallel
139 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000141 codegen->EmitParallelMoves(
142 index_location_,
143 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
144 length_location_,
145 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100146 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000147 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100148 }
149
150 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 const Location index_location_;
153 const Location length_location_;
154
155 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
156};
157
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000158class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100159 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000160 LoadClassSlowPathARM(HLoadClass* cls,
161 HInstruction* at,
162 uint32_t dex_pc,
163 bool do_clinit)
164 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
165 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
166 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100167
Alexandre Rames67555f72014-11-18 10:55:16 +0000168 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000169 LocationSummary* locations = at_->GetLocations();
170
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100171 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
172 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000173 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100174
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100175 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000176 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100177 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000178 int32_t entry_point_offset = do_clinit_
179 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
180 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000181 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000182
183 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000184 Location out = locations->Out();
185 if (out.IsValid()) {
186 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000187 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
188 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000189 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 __ b(GetExitLabel());
191 }
192
193 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000194 // The class this slow path will load.
195 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 // The instruction where this slow path is happening.
198 // (Might be the load class or an initialization check).
199 HInstruction* const at_;
200
201 // The dex PC of `at_`.
202 const uint32_t dex_pc_;
203
204 // Whether to initialize the class.
205 const bool do_clinit_;
206
207 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208};
209
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000210class LoadStringSlowPathARM : public SlowPathCodeARM {
211 public:
212 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
213
Alexandre Rames67555f72014-11-18 10:55:16 +0000214 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000215 LocationSummary* locations = instruction_->GetLocations();
216 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
217
218 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
219 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000220 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000221
222 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800223 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
224 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000225 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000226 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000227 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
228
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000229 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000230 __ b(GetExitLabel());
231 }
232
233 private:
234 HLoadString* const instruction_;
235
236 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
237};
238
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000239class TypeCheckSlowPathARM : public SlowPathCodeARM {
240 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000241 TypeCheckSlowPathARM(HInstruction* instruction,
242 Location class_to_check,
243 Location object_class,
244 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000245 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000246 class_to_check_(class_to_check),
247 object_class_(object_class),
248 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000249
Alexandre Rames67555f72014-11-18 10:55:16 +0000250 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000251 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000252 DCHECK(instruction_->IsCheckCast()
253 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000254
255 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
256 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000257 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000258
259 // We're moving two locations to locations that could overlap, so we need a parallel
260 // move resolver.
261 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000262 codegen->EmitParallelMoves(
263 class_to_check_,
264 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
265 object_class_,
266 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000267
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000268 if (instruction_->IsInstanceOf()) {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000269 arm_codegen->InvokeRuntime(
270 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000271 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
272 } else {
273 DCHECK(instruction_->IsCheckCast());
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000274 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000275 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000277 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278 __ b(GetExitLabel());
279 }
280
281 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000282 HInstruction* const instruction_;
283 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000285 uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286
287 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
288};
289
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700290class DeoptimizationSlowPathARM : public SlowPathCodeARM {
291 public:
292 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
293 : instruction_(instruction) {}
294
295 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
296 __ Bind(GetEntryLabel());
297 SaveLiveRegisters(codegen, instruction_->GetLocations());
298 DCHECK(instruction_->IsDeoptimize());
299 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
300 uint32_t dex_pc = deoptimize->GetDexPc();
301 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
302 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
303 }
304
305 private:
306 HInstruction* const instruction_;
307 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
308};
309
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000310#undef __
311
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100312#undef __
313#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700314
315inline Condition ARMCondition(IfCondition cond) {
316 switch (cond) {
317 case kCondEQ: return EQ;
318 case kCondNE: return NE;
319 case kCondLT: return LT;
320 case kCondLE: return LE;
321 case kCondGT: return GT;
322 case kCondGE: return GE;
323 default:
324 LOG(FATAL) << "Unknown if condition";
325 }
326 return EQ; // Unreachable.
327}
328
329inline Condition ARMOppositeCondition(IfCondition cond) {
330 switch (cond) {
331 case kCondEQ: return NE;
332 case kCondNE: return EQ;
333 case kCondLT: return GE;
334 case kCondLE: return GT;
335 case kCondGT: return LE;
336 case kCondGE: return LT;
337 default:
338 LOG(FATAL) << "Unknown if condition";
339 }
340 return EQ; // Unreachable.
341}
342
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100343void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
344 stream << ArmManagedRegister::FromCoreRegister(Register(reg));
345}
346
347void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000348 stream << ArmManagedRegister::FromSRegister(SRegister(reg));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100349}
350
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100351size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
352 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
353 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100354}
355
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100356size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
357 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
358 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100359}
360
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000361size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
362 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
363 return kArmWordSize;
364}
365
366size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
367 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
368 return kArmWordSize;
369}
370
Calin Juravle34166012014-12-19 17:22:29 +0000371CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000372 const ArmInstructionSetFeatures& isa_features,
373 const CompilerOptions& compiler_options)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000374 : CodeGenerator(graph,
375 kNumberOfCoreRegisters,
376 kNumberOfSRegisters,
377 kNumberOfRegisterPairs,
378 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
379 arraysize(kCoreCalleeSaves)),
380 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
381 arraysize(kFpuCalleeSaves)),
382 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100383 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100384 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100385 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100386 move_resolver_(graph->GetArena(), this),
Calin Juravle34166012014-12-19 17:22:29 +0000387 assembler_(true),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000388 isa_features_(isa_features) {
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000389 // Save the PC register to mimic Quick.
390 AddAllocatedRegister(Location::RegisterLocation(PC));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100391}
392
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100393Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100394 switch (type) {
395 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100396 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100397 ArmManagedRegister pair =
398 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100399 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
400 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
401
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100402 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
403 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100404 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100405 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100406 }
407
408 case Primitive::kPrimByte:
409 case Primitive::kPrimBoolean:
410 case Primitive::kPrimChar:
411 case Primitive::kPrimShort:
412 case Primitive::kPrimInt:
413 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100414 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100415 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100416 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
417 ArmManagedRegister current =
418 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
419 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100420 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100421 }
422 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100423 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100424 }
425
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000426 case Primitive::kPrimFloat: {
427 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100428 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100429 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100430
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000431 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000432 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
433 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000434 return Location::FpuRegisterPairLocation(reg, reg + 1);
435 }
436
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100437 case Primitive::kPrimVoid:
438 LOG(FATAL) << "Unreachable type " << type;
439 }
440
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100441 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100442}
443
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000444void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100445 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100446 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100447
448 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100449 blocked_core_registers_[SP] = true;
450 blocked_core_registers_[LR] = true;
451 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100452
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100453 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100454 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100455
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100456 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100457 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100458
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000459 if (is_baseline) {
460 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
461 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
462 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000463
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000464 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
465
466 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
467 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
468 }
469 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100470
471 UpdateBlockedPairRegisters();
472}
473
474void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
475 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
476 ArmManagedRegister current =
477 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
478 if (blocked_core_registers_[current.AsRegisterPairLow()]
479 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
480 blocked_register_pairs_[i] = true;
481 }
482 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100483}
484
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100485InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
486 : HGraphVisitor(graph),
487 assembler_(codegen->GetAssembler()),
488 codegen_(codegen) {}
489
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000490static uint32_t LeastSignificantBit(uint32_t mask) {
491 // ffs starts at 1.
492 return ffs(mask) - 1;
493}
494
495void CodeGeneratorARM::ComputeSpillMask() {
496 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000497 // Save one extra register for baseline. Note that on thumb2, there is no easy
498 // instruction to restore just the PC, so this actually helps both baseline
499 // and non-baseline to save and restore at least two registers at entry and exit.
500 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000501 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
502 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
503 // We use vpush and vpop for saving and restoring floating point registers, which take
504 // a SRegister and the number of registers to save/restore after that SRegister. We
505 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
506 // but in the range.
507 if (fpu_spill_mask_ != 0) {
508 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
509 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
510 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
511 fpu_spill_mask_ |= (1 << i);
512 }
513 }
514}
515
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000516void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000517 bool skip_overflow_check =
518 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000519 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000520 __ Bind(&frame_entry_label_);
521
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000522 if (HasEmptyFrame()) {
523 return;
524 }
525
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100526 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000527 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
528 __ LoadFromOffset(kLoadWord, IP, IP, 0);
529 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100530 }
531
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000532 // PC is in the list of callee-save to mimic Quick, but we need to push
533 // LR at entry instead.
534 __ PushList((core_spill_mask_ & (~(1 << PC))) | 1 << LR);
535 if (fpu_spill_mask_ != 0) {
536 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
537 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
538 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000539 __ AddConstant(SP, -(GetFrameSize() - FrameEntrySpillSize()));
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100540 __ StoreToOffset(kStoreWord, R0, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000541}
542
543void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000544 if (HasEmptyFrame()) {
545 __ bx(LR);
546 return;
547 }
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000548 __ AddConstant(SP, GetFrameSize() - FrameEntrySpillSize());
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000549 if (fpu_spill_mask_ != 0) {
550 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
551 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
552 }
553 __ PopList(core_spill_mask_);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000554}
555
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100556void CodeGeneratorARM::Bind(HBasicBlock* block) {
557 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000558}
559
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100560Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
561 switch (load->GetType()) {
562 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100563 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100564 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
565 break;
566
567 case Primitive::kPrimInt:
568 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100569 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100570 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100571
572 case Primitive::kPrimBoolean:
573 case Primitive::kPrimByte:
574 case Primitive::kPrimChar:
575 case Primitive::kPrimShort:
576 case Primitive::kPrimVoid:
577 LOG(FATAL) << "Unexpected type " << load->GetType();
578 }
579
580 LOG(FATAL) << "Unreachable";
581 return Location();
582}
583
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100584Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
585 switch (type) {
586 case Primitive::kPrimBoolean:
587 case Primitive::kPrimByte:
588 case Primitive::kPrimChar:
589 case Primitive::kPrimShort:
590 case Primitive::kPrimInt:
591 case Primitive::kPrimNot: {
592 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000593 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100594 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100595 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100596 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000597 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100598 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100599 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100600
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000601 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100602 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000603 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100604 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000605 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100606 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000607 if (calling_convention.GetRegisterAt(index) == R1) {
608 // Skip R1, and use R2_R3 instead.
609 gp_index_++;
610 index++;
611 }
612 }
613 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
614 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000615 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000616 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000617 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100618 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000619 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
620 }
621 }
622
623 case Primitive::kPrimFloat: {
624 uint32_t stack_index = stack_index_++;
625 if (float_index_ % 2 == 0) {
626 float_index_ = std::max(double_index_, float_index_);
627 }
628 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
629 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
630 } else {
631 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
632 }
633 }
634
635 case Primitive::kPrimDouble: {
636 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
637 uint32_t stack_index = stack_index_;
638 stack_index_ += 2;
639 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
640 uint32_t index = double_index_;
641 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000642 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000643 calling_convention.GetFpuRegisterAt(index),
644 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000645 DCHECK(ExpectedPairLayout(result));
646 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000647 } else {
648 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100649 }
650 }
651
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100652 case Primitive::kPrimVoid:
653 LOG(FATAL) << "Unexpected parameter type " << type;
654 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100655 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100656 return Location();
657}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100658
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000659Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
660 switch (type) {
661 case Primitive::kPrimBoolean:
662 case Primitive::kPrimByte:
663 case Primitive::kPrimChar:
664 case Primitive::kPrimShort:
665 case Primitive::kPrimInt:
666 case Primitive::kPrimNot: {
667 return Location::RegisterLocation(R0);
668 }
669
670 case Primitive::kPrimFloat: {
671 return Location::FpuRegisterLocation(S0);
672 }
673
674 case Primitive::kPrimLong: {
675 return Location::RegisterPairLocation(R0, R1);
676 }
677
678 case Primitive::kPrimDouble: {
679 return Location::FpuRegisterPairLocation(S0, S1);
680 }
681
682 case Primitive::kPrimVoid:
683 return Location();
684 }
685 UNREACHABLE();
686 return Location();
687}
688
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100689void CodeGeneratorARM::Move32(Location destination, Location source) {
690 if (source.Equals(destination)) {
691 return;
692 }
693 if (destination.IsRegister()) {
694 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000695 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100696 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000697 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100698 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000699 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100700 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100701 } else if (destination.IsFpuRegister()) {
702 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000703 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100704 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000705 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100706 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000707 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100708 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100709 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000710 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100711 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000712 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100713 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000714 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100715 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000716 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100717 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
718 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100719 }
720 }
721}
722
723void CodeGeneratorARM::Move64(Location destination, Location source) {
724 if (source.Equals(destination)) {
725 return;
726 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100727 if (destination.IsRegisterPair()) {
728 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000729 EmitParallelMoves(
730 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
731 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
732 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
733 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100734 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000735 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100736 } else {
737 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000738 DCHECK(ExpectedPairLayout(destination));
739 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
740 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000742 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100743 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000744 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
745 SP,
746 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100747 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000748 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100749 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100750 } else {
751 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100752 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000753 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100754 if (source.AsRegisterPairLow<Register>() == R1) {
755 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100756 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
757 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100758 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100759 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100760 SP, destination.GetStackIndex());
761 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000762 } else if (source.IsFpuRegisterPair()) {
763 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
764 SP,
765 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100766 } else {
767 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000768 EmitParallelMoves(
769 Location::StackSlot(source.GetStackIndex()),
770 Location::StackSlot(destination.GetStackIndex()),
771 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
772 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100773 }
774 }
775}
776
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100777void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100778 LocationSummary* locations = instruction->GetLocations();
779 if (locations != nullptr && locations->Out().Equals(location)) {
780 return;
781 }
782
Calin Juravlea21f5982014-11-13 15:53:04 +0000783 if (locations != nullptr && locations->Out().IsConstant()) {
784 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000785 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
786 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000787 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000788 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000789 } else {
790 DCHECK(location.IsStackSlot());
791 __ LoadImmediate(IP, value);
792 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
793 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000794 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000795 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000796 int64_t value = const_to_move->AsLongConstant()->GetValue();
797 if (location.IsRegisterPair()) {
798 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
799 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
800 } else {
801 DCHECK(location.IsDoubleStackSlot());
802 __ LoadImmediate(IP, Low32Bits(value));
803 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
804 __ LoadImmediate(IP, High32Bits(value));
805 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
806 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100807 }
Roland Levillain476df552014-10-09 17:51:36 +0100808 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
810 switch (instruction->GetType()) {
811 case Primitive::kPrimBoolean:
812 case Primitive::kPrimByte:
813 case Primitive::kPrimChar:
814 case Primitive::kPrimShort:
815 case Primitive::kPrimInt:
816 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100817 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100818 Move32(location, Location::StackSlot(stack_slot));
819 break;
820
821 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100822 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100823 Move64(location, Location::DoubleStackSlot(stack_slot));
824 break;
825
826 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100827 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100828 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000829 } else if (instruction->IsTemporary()) {
830 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000831 if (temp_location.IsStackSlot()) {
832 Move32(location, temp_location);
833 } else {
834 DCHECK(temp_location.IsDoubleStackSlot());
835 Move64(location, temp_location);
836 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000837 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100838 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100839 switch (instruction->GetType()) {
840 case Primitive::kPrimBoolean:
841 case Primitive::kPrimByte:
842 case Primitive::kPrimChar:
843 case Primitive::kPrimShort:
844 case Primitive::kPrimNot:
845 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100846 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100847 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100848 break;
849
850 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100851 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100852 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100853 break;
854
855 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100856 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100857 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000858 }
859}
860
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100861void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
862 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000863 uint32_t dex_pc,
864 SlowPathCode* slow_path) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100865 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
866 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000867 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100868 DCHECK(instruction->IsSuspendCheck()
869 || instruction->IsBoundsCheck()
870 || instruction->IsNullCheck()
Calin Juravled0d48522014-11-04 16:40:20 +0000871 || instruction->IsDivZeroCheck()
Roland Levillain624279f2014-12-04 11:54:28 +0000872 || instruction->GetLocations()->CanCall()
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100873 || !IsLeafMethod());
874}
875
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000876void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000877 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000878}
879
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000880void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000881 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100882 DCHECK(!successor->IsExitBlock());
883
884 HBasicBlock* block = got->GetBlock();
885 HInstruction* previous = got->GetPrevious();
886
887 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000888 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100889 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
890 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
891 return;
892 }
893
894 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
895 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
896 }
897 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000898 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000899 }
900}
901
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000902void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000903 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000904}
905
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000906void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700907 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000908}
909
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700910void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
911 Label* true_target,
912 Label* false_target,
913 Label* always_true_target) {
914 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100915 if (cond->IsIntConstant()) {
916 // Constant condition, statically compared against 1.
917 int32_t cond_value = cond->AsIntConstant()->GetValue();
918 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700919 if (always_true_target != nullptr) {
920 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100921 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100922 return;
923 } else {
924 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100925 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100926 } else {
927 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
928 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700929 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
930 __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100931 ShifterOperand(0));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700932 __ b(true_target, NE);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100933 } else {
934 // Condition has not been materialized, use its inputs as the
935 // comparison and its condition as the branch condition.
936 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000937 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000938 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100939 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000940 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100941 } else {
942 DCHECK(locations->InAt(1).IsConstant());
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000943 HConstant* constant = locations->InAt(1).GetConstant();
944 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100945 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000946 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
947 __ cmp(left, operand);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100948 } else {
949 Register temp = IP;
950 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000951 __ cmp(left, ShifterOperand(temp));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100952 }
953 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700954 __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100955 }
Dave Allison20dfc792014-06-16 20:44:29 -0700956 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700957 if (false_target != nullptr) {
958 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000959 }
960}
961
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700962void LocationsBuilderARM::VisitIf(HIf* if_instr) {
963 LocationSummary* locations =
964 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
965 HInstruction* cond = if_instr->InputAt(0);
966 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
967 locations->SetInAt(0, Location::RequiresRegister());
968 }
969}
970
971void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
972 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
973 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
974 Label* always_true_target = true_target;
975 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
976 if_instr->IfTrueSuccessor())) {
977 always_true_target = nullptr;
978 }
979 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
980 if_instr->IfFalseSuccessor())) {
981 false_target = nullptr;
982 }
983 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
984}
985
986void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
987 LocationSummary* locations = new (GetGraph()->GetArena())
988 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
989 HInstruction* cond = deoptimize->InputAt(0);
990 DCHECK(cond->IsCondition());
991 if (cond->AsCondition()->NeedsMaterialization()) {
992 locations->SetInAt(0, Location::RequiresRegister());
993 }
994}
995
996void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
997 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
998 DeoptimizationSlowPathARM(deoptimize);
999 codegen_->AddSlowPath(slow_path);
1000 Label* slow_path_entry = slow_path->GetEntryLabel();
1001 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1002}
Dave Allison20dfc792014-06-16 20:44:29 -07001003
1004void LocationsBuilderARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001005 LocationSummary* locations =
1006 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001007 locations->SetInAt(0, Location::RequiresRegister());
1008 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001009 if (comp->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001010 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001011 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001012}
1013
Dave Allison20dfc792014-06-16 20:44:29 -07001014void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001015 if (!comp->NeedsMaterialization()) return;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001016 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001017 Register left = locations->InAt(0).AsRegister<Register>();
1018
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001019 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001020 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001021 } else {
1022 DCHECK(locations->InAt(1).IsConstant());
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001023 int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001024 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001025 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
1026 __ cmp(left, operand);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001027 } else {
1028 Register temp = IP;
1029 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001030 __ cmp(left, ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 }
Dave Allison20dfc792014-06-16 20:44:29 -07001032 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001033 __ it(ARMCondition(comp->GetCondition()), kItElse);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001034 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001035 ARMCondition(comp->GetCondition()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001036 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001037 ARMOppositeCondition(comp->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -07001038}
1039
1040void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1041 VisitCondition(comp);
1042}
1043
1044void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1045 VisitCondition(comp);
1046}
1047
1048void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1049 VisitCondition(comp);
1050}
1051
1052void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1053 VisitCondition(comp);
1054}
1055
1056void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1057 VisitCondition(comp);
1058}
1059
1060void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1061 VisitCondition(comp);
1062}
1063
1064void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1065 VisitCondition(comp);
1066}
1067
1068void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1069 VisitCondition(comp);
1070}
1071
1072void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1073 VisitCondition(comp);
1074}
1075
1076void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1077 VisitCondition(comp);
1078}
1079
1080void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1081 VisitCondition(comp);
1082}
1083
1084void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1085 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001086}
1087
1088void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001089 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001090}
1091
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001092void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1093 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001094}
1095
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001096void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001097 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001098}
1099
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001100void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001101 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001102 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001103}
1104
1105void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001106 LocationSummary* locations =
1107 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001108 switch (store->InputAt(1)->GetType()) {
1109 case Primitive::kPrimBoolean:
1110 case Primitive::kPrimByte:
1111 case Primitive::kPrimChar:
1112 case Primitive::kPrimShort:
1113 case Primitive::kPrimInt:
1114 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001115 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001116 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1117 break;
1118
1119 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001120 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001121 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1122 break;
1123
1124 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001125 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001126 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001127}
1128
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001129void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001130 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001131}
1132
1133void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001134 LocationSummary* locations =
1135 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001136 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001137}
1138
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001139void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001140 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001141 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001142}
1143
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001144void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1145 LocationSummary* locations =
1146 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1147 locations->SetOut(Location::ConstantLocation(constant));
1148}
1149
1150void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1151 // Will be generated at use site.
1152 UNUSED(constant);
1153}
1154
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001155void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001156 LocationSummary* locations =
1157 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001158 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001159}
1160
1161void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1162 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001163 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001164}
1165
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001166void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1167 LocationSummary* locations =
1168 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1169 locations->SetOut(Location::ConstantLocation(constant));
1170}
1171
1172void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1173 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001174 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001175}
1176
1177void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1178 LocationSummary* locations =
1179 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1180 locations->SetOut(Location::ConstantLocation(constant));
1181}
1182
1183void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1184 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001185 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001186}
1187
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001188void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001189 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001190}
1191
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001192void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001193 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001194 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001195}
1196
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001197void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001198 LocationSummary* locations =
1199 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001200 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001201}
1202
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001203void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001204 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001205 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001206}
1207
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001208void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001209 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1210 codegen_->GetInstructionSetFeatures());
1211 if (intrinsic.TryDispatch(invoke)) {
1212 return;
1213 }
1214
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001215 HandleInvoke(invoke);
1216}
1217
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001218void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001219 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001220 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001221}
1222
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001223static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1224 if (invoke->GetLocations()->Intrinsified()) {
1225 IntrinsicCodeGeneratorARM intrinsic(codegen);
1226 intrinsic.Dispatch(invoke);
1227 return true;
1228 }
1229 return false;
1230}
1231
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001232void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001233 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1234 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001235 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001236
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001237 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1238
1239 codegen_->GenerateStaticOrDirectCall(invoke, temp);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001240 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001241}
1242
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001243void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001244 LocationSummary* locations =
1245 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001246 locations->AddTemp(Location::RegisterLocation(R0));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001247
1248 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001249 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001250 HInstruction* input = invoke->InputAt(i);
1251 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1252 }
1253
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001254 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001255}
1256
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001257void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001258 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1259 codegen_->GetInstructionSetFeatures());
1260 if (intrinsic.TryDispatch(invoke)) {
1261 return;
1262 }
1263
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001264 HandleInvoke(invoke);
1265}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001266
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001267void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001268 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1269 return;
1270 }
1271
Roland Levillain271ab9c2014-11-27 15:23:57 +00001272 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001273 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1274 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1275 LocationSummary* locations = invoke->GetLocations();
1276 Location receiver = locations->InAt(0);
1277 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1278 // temp = object->GetClass();
1279 if (receiver.IsStackSlot()) {
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001280 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1281 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001282 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001283 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001284 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001285 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001286 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001287 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001288 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001289 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001290 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001291 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001292 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001293 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001294 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001295 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001296}
1297
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001298void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1299 HandleInvoke(invoke);
1300 // Add the hidden argument.
1301 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1302}
1303
1304void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1305 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001306 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001307 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1308 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1309 LocationSummary* locations = invoke->GetLocations();
1310 Location receiver = locations->InAt(0);
1311 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1312
1313 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001314 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1315 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001316
1317 // temp = object->GetClass();
1318 if (receiver.IsStackSlot()) {
1319 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1320 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1321 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001322 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001323 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001324 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001325 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartier2d721012014-11-10 11:08:06 -08001326 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001327 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001328 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1329 // LR = temp->GetEntryPoint();
1330 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1331 // LR();
1332 __ blx(LR);
1333 DCHECK(!codegen_->IsLeafMethod());
1334 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1335}
1336
Roland Levillain88cb1752014-10-20 16:36:47 +01001337void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1338 LocationSummary* locations =
1339 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1340 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001341 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001342 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001343 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1344 break;
1345 }
1346 case Primitive::kPrimLong: {
1347 locations->SetInAt(0, Location::RequiresRegister());
1348 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001349 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001350 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001351
Roland Levillain88cb1752014-10-20 16:36:47 +01001352 case Primitive::kPrimFloat:
1353 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001354 locations->SetInAt(0, Location::RequiresFpuRegister());
1355 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001356 break;
1357
1358 default:
1359 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1360 }
1361}
1362
1363void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1364 LocationSummary* locations = neg->GetLocations();
1365 Location out = locations->Out();
1366 Location in = locations->InAt(0);
1367 switch (neg->GetResultType()) {
1368 case Primitive::kPrimInt:
1369 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001370 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001371 break;
1372
1373 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001374 DCHECK(in.IsRegisterPair());
1375 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1376 __ rsbs(out.AsRegisterPairLow<Register>(),
1377 in.AsRegisterPairLow<Register>(),
1378 ShifterOperand(0));
1379 // We cannot emit an RSC (Reverse Subtract with Carry)
1380 // instruction here, as it does not exist in the Thumb-2
1381 // instruction set. We use the following approach
1382 // using SBC and SUB instead.
1383 //
1384 // out.hi = -C
1385 __ sbc(out.AsRegisterPairHigh<Register>(),
1386 out.AsRegisterPairHigh<Register>(),
1387 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1388 // out.hi = out.hi - in.hi
1389 __ sub(out.AsRegisterPairHigh<Register>(),
1390 out.AsRegisterPairHigh<Register>(),
1391 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1392 break;
1393
Roland Levillain88cb1752014-10-20 16:36:47 +01001394 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001395 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001396 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001397 break;
1398
Roland Levillain88cb1752014-10-20 16:36:47 +01001399 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001400 DCHECK(in.IsFpuRegisterPair());
1401 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1402 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001403 break;
1404
1405 default:
1406 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1407 }
1408}
1409
Roland Levillaindff1f282014-11-05 14:15:05 +00001410void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001411 Primitive::Type result_type = conversion->GetResultType();
1412 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001413 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001414
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001415 // The float-to-long and double-to-long type conversions rely on a
1416 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001417 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001418 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1419 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001420 ? LocationSummary::kCall
1421 : LocationSummary::kNoCall;
1422 LocationSummary* locations =
1423 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1424
David Brazdilb2bd1c52015-03-25 11:17:37 +00001425 // The Java language does not allow treating boolean as an integral type but
1426 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001427
Roland Levillaindff1f282014-11-05 14:15:05 +00001428 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001429 case Primitive::kPrimByte:
1430 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001431 case Primitive::kPrimBoolean:
1432 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001433 case Primitive::kPrimShort:
1434 case Primitive::kPrimInt:
1435 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001436 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001437 locations->SetInAt(0, Location::RequiresRegister());
1438 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1439 break;
1440
1441 default:
1442 LOG(FATAL) << "Unexpected type conversion from " << input_type
1443 << " to " << result_type;
1444 }
1445 break;
1446
Roland Levillain01a8d712014-11-14 16:27:39 +00001447 case Primitive::kPrimShort:
1448 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001449 case Primitive::kPrimBoolean:
1450 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001451 case Primitive::kPrimByte:
1452 case Primitive::kPrimInt:
1453 case Primitive::kPrimChar:
1454 // Processing a Dex `int-to-short' instruction.
1455 locations->SetInAt(0, Location::RequiresRegister());
1456 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1457 break;
1458
1459 default:
1460 LOG(FATAL) << "Unexpected type conversion from " << input_type
1461 << " to " << result_type;
1462 }
1463 break;
1464
Roland Levillain946e1432014-11-11 17:35:19 +00001465 case Primitive::kPrimInt:
1466 switch (input_type) {
1467 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001468 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001469 locations->SetInAt(0, Location::Any());
1470 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1471 break;
1472
1473 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001474 // Processing a Dex `float-to-int' instruction.
1475 locations->SetInAt(0, Location::RequiresFpuRegister());
1476 locations->SetOut(Location::RequiresRegister());
1477 locations->AddTemp(Location::RequiresFpuRegister());
1478 break;
1479
Roland Levillain946e1432014-11-11 17:35:19 +00001480 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001481 // Processing a Dex `double-to-int' instruction.
1482 locations->SetInAt(0, Location::RequiresFpuRegister());
1483 locations->SetOut(Location::RequiresRegister());
1484 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001485 break;
1486
1487 default:
1488 LOG(FATAL) << "Unexpected type conversion from " << input_type
1489 << " to " << result_type;
1490 }
1491 break;
1492
Roland Levillaindff1f282014-11-05 14:15:05 +00001493 case Primitive::kPrimLong:
1494 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001495 case Primitive::kPrimBoolean:
1496 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001497 case Primitive::kPrimByte:
1498 case Primitive::kPrimShort:
1499 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001500 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001501 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001502 locations->SetInAt(0, Location::RequiresRegister());
1503 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1504 break;
1505
Roland Levillain624279f2014-12-04 11:54:28 +00001506 case Primitive::kPrimFloat: {
1507 // Processing a Dex `float-to-long' instruction.
1508 InvokeRuntimeCallingConvention calling_convention;
1509 locations->SetInAt(0, Location::FpuRegisterLocation(
1510 calling_convention.GetFpuRegisterAt(0)));
1511 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1512 break;
1513 }
1514
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001515 case Primitive::kPrimDouble: {
1516 // Processing a Dex `double-to-long' instruction.
1517 InvokeRuntimeCallingConvention calling_convention;
1518 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1519 calling_convention.GetFpuRegisterAt(0),
1520 calling_convention.GetFpuRegisterAt(1)));
1521 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001522 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001523 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001524
1525 default:
1526 LOG(FATAL) << "Unexpected type conversion from " << input_type
1527 << " to " << result_type;
1528 }
1529 break;
1530
Roland Levillain981e4542014-11-14 11:47:14 +00001531 case Primitive::kPrimChar:
1532 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001533 case Primitive::kPrimBoolean:
1534 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001535 case Primitive::kPrimByte:
1536 case Primitive::kPrimShort:
1537 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001538 // Processing a Dex `int-to-char' instruction.
1539 locations->SetInAt(0, Location::RequiresRegister());
1540 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1541 break;
1542
1543 default:
1544 LOG(FATAL) << "Unexpected type conversion from " << input_type
1545 << " to " << result_type;
1546 }
1547 break;
1548
Roland Levillaindff1f282014-11-05 14:15:05 +00001549 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001550 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001551 case Primitive::kPrimBoolean:
1552 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001553 case Primitive::kPrimByte:
1554 case Primitive::kPrimShort:
1555 case Primitive::kPrimInt:
1556 case Primitive::kPrimChar:
1557 // Processing a Dex `int-to-float' instruction.
1558 locations->SetInAt(0, Location::RequiresRegister());
1559 locations->SetOut(Location::RequiresFpuRegister());
1560 break;
1561
1562 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001563 // Processing a Dex `long-to-float' instruction.
1564 locations->SetInAt(0, Location::RequiresRegister());
1565 locations->SetOut(Location::RequiresFpuRegister());
1566 locations->AddTemp(Location::RequiresRegister());
1567 locations->AddTemp(Location::RequiresRegister());
1568 locations->AddTemp(Location::RequiresFpuRegister());
1569 locations->AddTemp(Location::RequiresFpuRegister());
1570 break;
1571
Roland Levillaincff13742014-11-17 14:32:17 +00001572 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001573 // Processing a Dex `double-to-float' instruction.
1574 locations->SetInAt(0, Location::RequiresFpuRegister());
1575 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001576 break;
1577
1578 default:
1579 LOG(FATAL) << "Unexpected type conversion from " << input_type
1580 << " to " << result_type;
1581 };
1582 break;
1583
Roland Levillaindff1f282014-11-05 14:15:05 +00001584 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001585 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001586 case Primitive::kPrimBoolean:
1587 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001588 case Primitive::kPrimByte:
1589 case Primitive::kPrimShort:
1590 case Primitive::kPrimInt:
1591 case Primitive::kPrimChar:
1592 // Processing a Dex `int-to-double' instruction.
1593 locations->SetInAt(0, Location::RequiresRegister());
1594 locations->SetOut(Location::RequiresFpuRegister());
1595 break;
1596
1597 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001598 // Processing a Dex `long-to-double' instruction.
1599 locations->SetInAt(0, Location::RequiresRegister());
1600 locations->SetOut(Location::RequiresFpuRegister());
1601 locations->AddTemp(Location::RequiresRegister());
1602 locations->AddTemp(Location::RequiresRegister());
1603 locations->AddTemp(Location::RequiresFpuRegister());
1604 break;
1605
Roland Levillaincff13742014-11-17 14:32:17 +00001606 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001607 // Processing a Dex `float-to-double' instruction.
1608 locations->SetInAt(0, Location::RequiresFpuRegister());
1609 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001610 break;
1611
1612 default:
1613 LOG(FATAL) << "Unexpected type conversion from " << input_type
1614 << " to " << result_type;
1615 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001616 break;
1617
1618 default:
1619 LOG(FATAL) << "Unexpected type conversion from " << input_type
1620 << " to " << result_type;
1621 }
1622}
1623
1624void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1625 LocationSummary* locations = conversion->GetLocations();
1626 Location out = locations->Out();
1627 Location in = locations->InAt(0);
1628 Primitive::Type result_type = conversion->GetResultType();
1629 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001630 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001631 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001632 case Primitive::kPrimByte:
1633 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001634 case Primitive::kPrimBoolean:
1635 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001636 case Primitive::kPrimShort:
1637 case Primitive::kPrimInt:
1638 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001639 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001640 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001641 break;
1642
1643 default:
1644 LOG(FATAL) << "Unexpected type conversion from " << input_type
1645 << " to " << result_type;
1646 }
1647 break;
1648
Roland Levillain01a8d712014-11-14 16:27:39 +00001649 case Primitive::kPrimShort:
1650 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001651 case Primitive::kPrimBoolean:
1652 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001653 case Primitive::kPrimByte:
1654 case Primitive::kPrimInt:
1655 case Primitive::kPrimChar:
1656 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001657 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001658 break;
1659
1660 default:
1661 LOG(FATAL) << "Unexpected type conversion from " << input_type
1662 << " to " << result_type;
1663 }
1664 break;
1665
Roland Levillain946e1432014-11-11 17:35:19 +00001666 case Primitive::kPrimInt:
1667 switch (input_type) {
1668 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001669 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001670 DCHECK(out.IsRegister());
1671 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001672 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001673 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001674 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001675 } else {
1676 DCHECK(in.IsConstant());
1677 DCHECK(in.GetConstant()->IsLongConstant());
1678 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001679 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001680 }
1681 break;
1682
Roland Levillain3f8f9362014-12-02 17:45:01 +00001683 case Primitive::kPrimFloat: {
1684 // Processing a Dex `float-to-int' instruction.
1685 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1686 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1687 __ vcvtis(temp, temp);
1688 __ vmovrs(out.AsRegister<Register>(), temp);
1689 break;
1690 }
1691
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001692 case Primitive::kPrimDouble: {
1693 // Processing a Dex `double-to-int' instruction.
1694 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1695 DRegister temp_d = FromLowSToD(temp_s);
1696 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1697 __ vcvtid(temp_s, temp_d);
1698 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001699 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001700 }
Roland Levillain946e1432014-11-11 17:35:19 +00001701
1702 default:
1703 LOG(FATAL) << "Unexpected type conversion from " << input_type
1704 << " to " << result_type;
1705 }
1706 break;
1707
Roland Levillaindff1f282014-11-05 14:15:05 +00001708 case Primitive::kPrimLong:
1709 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001710 case Primitive::kPrimBoolean:
1711 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001712 case Primitive::kPrimByte:
1713 case Primitive::kPrimShort:
1714 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001715 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001716 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001717 DCHECK(out.IsRegisterPair());
1718 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001719 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001720 // Sign extension.
1721 __ Asr(out.AsRegisterPairHigh<Register>(),
1722 out.AsRegisterPairLow<Register>(),
1723 31);
1724 break;
1725
1726 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001727 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00001728 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1729 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001730 conversion->GetDexPc(),
1731 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00001732 break;
1733
Roland Levillaindff1f282014-11-05 14:15:05 +00001734 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001735 // Processing a Dex `double-to-long' instruction.
1736 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1737 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001738 conversion->GetDexPc(),
1739 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00001740 break;
1741
1742 default:
1743 LOG(FATAL) << "Unexpected type conversion from " << input_type
1744 << " to " << result_type;
1745 }
1746 break;
1747
Roland Levillain981e4542014-11-14 11:47:14 +00001748 case Primitive::kPrimChar:
1749 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001750 case Primitive::kPrimBoolean:
1751 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001752 case Primitive::kPrimByte:
1753 case Primitive::kPrimShort:
1754 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001755 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001756 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00001757 break;
1758
1759 default:
1760 LOG(FATAL) << "Unexpected type conversion from " << input_type
1761 << " to " << result_type;
1762 }
1763 break;
1764
Roland Levillaindff1f282014-11-05 14:15:05 +00001765 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001766 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001767 case Primitive::kPrimBoolean:
1768 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001769 case Primitive::kPrimByte:
1770 case Primitive::kPrimShort:
1771 case Primitive::kPrimInt:
1772 case Primitive::kPrimChar: {
1773 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001774 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1775 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001776 break;
1777 }
1778
Roland Levillain6d0e4832014-11-27 18:31:21 +00001779 case Primitive::kPrimLong: {
1780 // Processing a Dex `long-to-float' instruction.
1781 Register low = in.AsRegisterPairLow<Register>();
1782 Register high = in.AsRegisterPairHigh<Register>();
1783 SRegister output = out.AsFpuRegister<SRegister>();
1784 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1785 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
1786 SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1787 DRegister temp1_d = FromLowSToD(temp1_s);
1788 SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
1789 DRegister temp2_d = FromLowSToD(temp2_s);
1790
1791 // Operations use doubles for precision reasons (each 32-bit
1792 // half of a long fits in the 53-bit mantissa of a double,
1793 // but not in the 24-bit mantissa of a float). This is
1794 // especially important for the low bits. The result is
1795 // eventually converted to float.
1796
1797 // temp1_d = int-to-double(high)
1798 __ vmovsr(temp1_s, high);
1799 __ vcvtdi(temp1_d, temp1_s);
1800 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1801 // as an immediate value into `temp2_d` does not work, as
1802 // this instruction only transfers 8 significant bits of its
1803 // immediate operand. Instead, use two 32-bit core
1804 // registers to load `k2Pow32EncodingForDouble` into
1805 // `temp2_d`.
1806 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1807 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
1808 __ vmovdrr(temp2_d, constant_low, constant_high);
1809 // temp1_d = temp1_d * 2^32
1810 __ vmuld(temp1_d, temp1_d, temp2_d);
1811 // temp2_d = unsigned-to-double(low)
1812 __ vmovsr(temp2_s, low);
1813 __ vcvtdu(temp2_d, temp2_s);
1814 // temp1_d = temp1_d + temp2_d
1815 __ vaddd(temp1_d, temp1_d, temp2_d);
1816 // output = double-to-float(temp1_d);
1817 __ vcvtsd(output, temp1_d);
1818 break;
1819 }
1820
Roland Levillaincff13742014-11-17 14:32:17 +00001821 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001822 // Processing a Dex `double-to-float' instruction.
1823 __ vcvtsd(out.AsFpuRegister<SRegister>(),
1824 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00001825 break;
1826
1827 default:
1828 LOG(FATAL) << "Unexpected type conversion from " << input_type
1829 << " to " << result_type;
1830 };
1831 break;
1832
Roland Levillaindff1f282014-11-05 14:15:05 +00001833 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001834 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001835 case Primitive::kPrimBoolean:
1836 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001837 case Primitive::kPrimByte:
1838 case Primitive::kPrimShort:
1839 case Primitive::kPrimInt:
1840 case Primitive::kPrimChar: {
1841 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001842 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001843 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1844 out.AsFpuRegisterPairLow<SRegister>());
1845 break;
1846 }
1847
Roland Levillain647b9ed2014-11-27 12:06:00 +00001848 case Primitive::kPrimLong: {
1849 // Processing a Dex `long-to-double' instruction.
1850 Register low = in.AsRegisterPairLow<Register>();
1851 Register high = in.AsRegisterPairHigh<Register>();
1852 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1853 DRegister out_d = FromLowSToD(out_s);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001854 Register constant_low = locations->GetTemp(0).AsRegister<Register>();
1855 Register constant_high = locations->GetTemp(1).AsRegister<Register>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001856 SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
1857 DRegister temp_d = FromLowSToD(temp_s);
1858
Roland Levillain647b9ed2014-11-27 12:06:00 +00001859 // out_d = int-to-double(high)
1860 __ vmovsr(out_s, high);
1861 __ vcvtdi(out_d, out_s);
Roland Levillain6d0e4832014-11-27 18:31:21 +00001862 // Using vmovd to load the `k2Pow32EncodingForDouble` constant
1863 // as an immediate value into `temp_d` does not work, as
1864 // this instruction only transfers 8 significant bits of its
1865 // immediate operand. Instead, use two 32-bit core
1866 // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
1867 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
1868 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001869 __ vmovdrr(temp_d, constant_low, constant_high);
1870 // out_d = out_d * 2^32
1871 __ vmuld(out_d, out_d, temp_d);
1872 // temp_d = unsigned-to-double(low)
1873 __ vmovsr(temp_s, low);
1874 __ vcvtdu(temp_d, temp_s);
1875 // out_d = out_d + temp_d
1876 __ vaddd(out_d, out_d, temp_d);
1877 break;
1878 }
1879
Roland Levillaincff13742014-11-17 14:32:17 +00001880 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001881 // Processing a Dex `float-to-double' instruction.
1882 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1883 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001884 break;
1885
1886 default:
1887 LOG(FATAL) << "Unexpected type conversion from " << input_type
1888 << " to " << result_type;
1889 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001890 break;
1891
1892 default:
1893 LOG(FATAL) << "Unexpected type conversion from " << input_type
1894 << " to " << result_type;
1895 }
1896}
1897
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001898void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001899 LocationSummary* locations =
1900 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001901 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001902 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001903 locations->SetInAt(0, Location::RequiresRegister());
1904 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001905 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1906 break;
1907 }
1908
1909 case Primitive::kPrimLong: {
1910 locations->SetInAt(0, Location::RequiresRegister());
1911 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001912 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001913 break;
1914 }
1915
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001916 case Primitive::kPrimFloat:
1917 case Primitive::kPrimDouble: {
1918 locations->SetInAt(0, Location::RequiresFpuRegister());
1919 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001920 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001921 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001922 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001923
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001924 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001925 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001926 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001927}
1928
1929void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1930 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001931 Location out = locations->Out();
1932 Location first = locations->InAt(0);
1933 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001934 switch (add->GetResultType()) {
1935 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001936 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001937 __ add(out.AsRegister<Register>(),
1938 first.AsRegister<Register>(),
1939 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001940 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001941 __ AddConstant(out.AsRegister<Register>(),
1942 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001943 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001944 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001945 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001946
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001947 case Primitive::kPrimLong: {
1948 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001949 __ adds(out.AsRegisterPairLow<Register>(),
1950 first.AsRegisterPairLow<Register>(),
1951 ShifterOperand(second.AsRegisterPairLow<Register>()));
1952 __ adc(out.AsRegisterPairHigh<Register>(),
1953 first.AsRegisterPairHigh<Register>(),
1954 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001955 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001956 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001957
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001958 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00001959 __ vadds(out.AsFpuRegister<SRegister>(),
1960 first.AsFpuRegister<SRegister>(),
1961 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001962 break;
1963
1964 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001965 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1966 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1967 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001968 break;
1969
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001970 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001971 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001972 }
1973}
1974
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001975void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001976 LocationSummary* locations =
1977 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001978 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001979 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001980 locations->SetInAt(0, Location::RequiresRegister());
1981 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001982 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1983 break;
1984 }
1985
1986 case Primitive::kPrimLong: {
1987 locations->SetInAt(0, Location::RequiresRegister());
1988 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001989 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001990 break;
1991 }
Calin Juravle11351682014-10-23 15:38:15 +01001992 case Primitive::kPrimFloat:
1993 case Primitive::kPrimDouble: {
1994 locations->SetInAt(0, Location::RequiresFpuRegister());
1995 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001996 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001997 break;
Calin Juravle11351682014-10-23 15:38:15 +01001998 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001999 default:
Calin Juravle11351682014-10-23 15:38:15 +01002000 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002001 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002002}
2003
2004void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2005 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002006 Location out = locations->Out();
2007 Location first = locations->InAt(0);
2008 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002009 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002010 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002011 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002012 __ sub(out.AsRegister<Register>(),
2013 first.AsRegister<Register>(),
2014 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002015 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002016 __ AddConstant(out.AsRegister<Register>(),
2017 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002018 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002019 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002020 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002021 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002022
Calin Juravle11351682014-10-23 15:38:15 +01002023 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002024 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002025 __ subs(out.AsRegisterPairLow<Register>(),
2026 first.AsRegisterPairLow<Register>(),
2027 ShifterOperand(second.AsRegisterPairLow<Register>()));
2028 __ sbc(out.AsRegisterPairHigh<Register>(),
2029 first.AsRegisterPairHigh<Register>(),
2030 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002031 break;
Calin Juravle11351682014-10-23 15:38:15 +01002032 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002033
Calin Juravle11351682014-10-23 15:38:15 +01002034 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002035 __ vsubs(out.AsFpuRegister<SRegister>(),
2036 first.AsFpuRegister<SRegister>(),
2037 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002038 break;
Calin Juravle11351682014-10-23 15:38:15 +01002039 }
2040
2041 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002042 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2043 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2044 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002045 break;
2046 }
2047
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002048
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002049 default:
Calin Juravle11351682014-10-23 15:38:15 +01002050 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002051 }
2052}
2053
Calin Juravle34bacdf2014-10-07 20:23:36 +01002054void LocationsBuilderARM::VisitMul(HMul* mul) {
2055 LocationSummary* locations =
2056 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2057 switch (mul->GetResultType()) {
2058 case Primitive::kPrimInt:
2059 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002060 locations->SetInAt(0, Location::RequiresRegister());
2061 locations->SetInAt(1, Location::RequiresRegister());
2062 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002063 break;
2064 }
2065
Calin Juravleb5bfa962014-10-21 18:02:24 +01002066 case Primitive::kPrimFloat:
2067 case Primitive::kPrimDouble: {
2068 locations->SetInAt(0, Location::RequiresFpuRegister());
2069 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002070 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002071 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002072 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002073
2074 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002075 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002076 }
2077}
2078
2079void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2080 LocationSummary* locations = mul->GetLocations();
2081 Location out = locations->Out();
2082 Location first = locations->InAt(0);
2083 Location second = locations->InAt(1);
2084 switch (mul->GetResultType()) {
2085 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002086 __ mul(out.AsRegister<Register>(),
2087 first.AsRegister<Register>(),
2088 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002089 break;
2090 }
2091 case Primitive::kPrimLong: {
2092 Register out_hi = out.AsRegisterPairHigh<Register>();
2093 Register out_lo = out.AsRegisterPairLow<Register>();
2094 Register in1_hi = first.AsRegisterPairHigh<Register>();
2095 Register in1_lo = first.AsRegisterPairLow<Register>();
2096 Register in2_hi = second.AsRegisterPairHigh<Register>();
2097 Register in2_lo = second.AsRegisterPairLow<Register>();
2098
2099 // Extra checks to protect caused by the existence of R1_R2.
2100 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2101 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2102 DCHECK_NE(out_hi, in1_lo);
2103 DCHECK_NE(out_hi, in2_lo);
2104
2105 // input: in1 - 64 bits, in2 - 64 bits
2106 // output: out
2107 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2108 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2109 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2110
2111 // IP <- in1.lo * in2.hi
2112 __ mul(IP, in1_lo, in2_hi);
2113 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2114 __ mla(out_hi, in1_hi, in2_lo, IP);
2115 // out.lo <- (in1.lo * in2.lo)[31:0];
2116 __ umull(out_lo, IP, in1_lo, in2_lo);
2117 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2118 __ add(out_hi, out_hi, ShifterOperand(IP));
2119 break;
2120 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002121
2122 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002123 __ vmuls(out.AsFpuRegister<SRegister>(),
2124 first.AsFpuRegister<SRegister>(),
2125 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002126 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002127 }
2128
2129 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002130 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2131 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2132 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002133 break;
2134 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002135
2136 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002137 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002138 }
2139}
2140
Calin Juravle7c4954d2014-10-28 16:57:40 +00002141void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002142 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2143 if (div->GetResultType() == Primitive::kPrimLong) {
2144 // pLdiv runtime call.
2145 call_kind = LocationSummary::kCall;
2146 } else if (div->GetResultType() == Primitive::kPrimInt &&
2147 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2148 // pIdivmod runtime call.
2149 call_kind = LocationSummary::kCall;
2150 }
2151
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002152 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2153
Calin Juravle7c4954d2014-10-28 16:57:40 +00002154 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002155 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002156 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2157 locations->SetInAt(0, Location::RequiresRegister());
2158 locations->SetInAt(1, Location::RequiresRegister());
2159 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2160 } else {
2161 InvokeRuntimeCallingConvention calling_convention;
2162 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2163 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2164 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2165 // we only need the former.
2166 locations->SetOut(Location::RegisterLocation(R0));
2167 }
Calin Juravled0d48522014-11-04 16:40:20 +00002168 break;
2169 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002170 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002171 InvokeRuntimeCallingConvention calling_convention;
2172 locations->SetInAt(0, Location::RegisterPairLocation(
2173 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2174 locations->SetInAt(1, Location::RegisterPairLocation(
2175 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002176 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002177 break;
2178 }
2179 case Primitive::kPrimFloat:
2180 case Primitive::kPrimDouble: {
2181 locations->SetInAt(0, Location::RequiresFpuRegister());
2182 locations->SetInAt(1, Location::RequiresFpuRegister());
2183 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2184 break;
2185 }
2186
2187 default:
2188 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2189 }
2190}
2191
2192void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2193 LocationSummary* locations = div->GetLocations();
2194 Location out = locations->Out();
2195 Location first = locations->InAt(0);
2196 Location second = locations->InAt(1);
2197
2198 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002199 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002200 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2201 __ sdiv(out.AsRegister<Register>(),
2202 first.AsRegister<Register>(),
2203 second.AsRegister<Register>());
2204 } else {
2205 InvokeRuntimeCallingConvention calling_convention;
2206 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2207 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2208 DCHECK_EQ(R0, out.AsRegister<Register>());
2209
2210 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2211 }
Calin Juravled0d48522014-11-04 16:40:20 +00002212 break;
2213 }
2214
Calin Juravle7c4954d2014-10-28 16:57:40 +00002215 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002216 InvokeRuntimeCallingConvention calling_convention;
2217 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2218 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2219 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2220 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2221 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002222 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002223
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002224 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002225 break;
2226 }
2227
2228 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002229 __ vdivs(out.AsFpuRegister<SRegister>(),
2230 first.AsFpuRegister<SRegister>(),
2231 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002232 break;
2233 }
2234
2235 case Primitive::kPrimDouble: {
2236 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2237 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2238 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2239 break;
2240 }
2241
2242 default:
2243 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2244 }
2245}
2246
Calin Juravlebacfec32014-11-14 15:54:36 +00002247void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002248 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002249
2250 // Most remainders are implemented in the runtime.
2251 LocationSummary::CallKind call_kind = LocationSummary::kCall;
2252 if (rem->GetResultType() == Primitive::kPrimInt &&
2253 codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2254 // Have hardware divide instruction for int, do it with three instructions.
2255 call_kind = LocationSummary::kNoCall;
2256 }
2257
Calin Juravlebacfec32014-11-14 15:54:36 +00002258 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2259
Calin Juravled2ec87d2014-12-08 14:24:46 +00002260 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002261 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002262 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2263 locations->SetInAt(0, Location::RequiresRegister());
2264 locations->SetInAt(1, Location::RequiresRegister());
2265 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2266 locations->AddTemp(Location::RequiresRegister());
2267 } else {
2268 InvokeRuntimeCallingConvention calling_convention;
2269 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2270 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2271 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2272 // we only need the latter.
2273 locations->SetOut(Location::RegisterLocation(R1));
2274 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002275 break;
2276 }
2277 case Primitive::kPrimLong: {
2278 InvokeRuntimeCallingConvention calling_convention;
2279 locations->SetInAt(0, Location::RegisterPairLocation(
2280 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2281 locations->SetInAt(1, Location::RegisterPairLocation(
2282 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2283 // The runtime helper puts the output in R2,R3.
2284 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2285 break;
2286 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002287 case Primitive::kPrimFloat: {
2288 InvokeRuntimeCallingConvention calling_convention;
2289 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2290 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2291 locations->SetOut(Location::FpuRegisterLocation(S0));
2292 break;
2293 }
2294
Calin Juravlebacfec32014-11-14 15:54:36 +00002295 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002296 InvokeRuntimeCallingConvention calling_convention;
2297 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2298 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2299 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2300 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2301 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002302 break;
2303 }
2304
2305 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002306 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002307 }
2308}
2309
2310void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2311 LocationSummary* locations = rem->GetLocations();
2312 Location out = locations->Out();
2313 Location first = locations->InAt(0);
2314 Location second = locations->InAt(1);
2315
Calin Juravled2ec87d2014-12-08 14:24:46 +00002316 Primitive::Type type = rem->GetResultType();
2317 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002318 case Primitive::kPrimInt: {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002319 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2320 Register reg1 = first.AsRegister<Register>();
2321 Register reg2 = second.AsRegister<Register>();
2322 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002323
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002324 // temp = reg1 / reg2 (integer division)
2325 // temp = temp * reg2
2326 // dest = reg1 - temp
2327 __ sdiv(temp, reg1, reg2);
2328 __ mul(temp, temp, reg2);
2329 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2330 } else {
2331 InvokeRuntimeCallingConvention calling_convention;
2332 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2333 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2334 DCHECK_EQ(R1, out.AsRegister<Register>());
2335
2336 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2337 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002338 break;
2339 }
2340
2341 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002342 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002343 break;
2344 }
2345
Calin Juravled2ec87d2014-12-08 14:24:46 +00002346 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002347 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002348 break;
2349 }
2350
Calin Juravlebacfec32014-11-14 15:54:36 +00002351 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002352 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002353 break;
2354 }
2355
2356 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002357 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002358 }
2359}
2360
Calin Juravled0d48522014-11-04 16:40:20 +00002361void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2362 LocationSummary* locations =
2363 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002364 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002365 if (instruction->HasUses()) {
2366 locations->SetOut(Location::SameAsFirstInput());
2367 }
2368}
2369
2370void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2371 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2372 codegen_->AddSlowPath(slow_path);
2373
2374 LocationSummary* locations = instruction->GetLocations();
2375 Location value = locations->InAt(0);
2376
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002377 switch (instruction->GetType()) {
2378 case Primitive::kPrimInt: {
2379 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002380 __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002381 __ b(slow_path->GetEntryLabel(), EQ);
2382 } else {
2383 DCHECK(value.IsConstant()) << value;
2384 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2385 __ b(slow_path->GetEntryLabel());
2386 }
2387 }
2388 break;
2389 }
2390 case Primitive::kPrimLong: {
2391 if (value.IsRegisterPair()) {
2392 __ orrs(IP,
2393 value.AsRegisterPairLow<Register>(),
2394 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2395 __ b(slow_path->GetEntryLabel(), EQ);
2396 } else {
2397 DCHECK(value.IsConstant()) << value;
2398 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2399 __ b(slow_path->GetEntryLabel());
2400 }
2401 }
2402 break;
2403 default:
2404 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2405 }
2406 }
Calin Juravled0d48522014-11-04 16:40:20 +00002407}
2408
Calin Juravle9aec02f2014-11-18 23:06:35 +00002409void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2410 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2411
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002412 LocationSummary* locations =
2413 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002414
2415 switch (op->GetResultType()) {
2416 case Primitive::kPrimInt: {
2417 locations->SetInAt(0, Location::RequiresRegister());
2418 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002419 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002420 break;
2421 }
2422 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002423 locations->SetInAt(0, Location::RequiresRegister());
2424 locations->SetInAt(1, Location::RequiresRegister());
2425 locations->AddTemp(Location::RequiresRegister());
2426 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002427 break;
2428 }
2429 default:
2430 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2431 }
2432}
2433
2434void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2435 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2436
2437 LocationSummary* locations = op->GetLocations();
2438 Location out = locations->Out();
2439 Location first = locations->InAt(0);
2440 Location second = locations->InAt(1);
2441
2442 Primitive::Type type = op->GetResultType();
2443 switch (type) {
2444 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002445 Register out_reg = out.AsRegister<Register>();
2446 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002447 // Arm doesn't mask the shift count so we need to do it ourselves.
2448 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002449 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002450 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2451 if (op->IsShl()) {
2452 __ Lsl(out_reg, first_reg, second_reg);
2453 } else if (op->IsShr()) {
2454 __ Asr(out_reg, first_reg, second_reg);
2455 } else {
2456 __ Lsr(out_reg, first_reg, second_reg);
2457 }
2458 } else {
2459 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2460 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2461 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2462 __ Mov(out_reg, first_reg);
2463 } else if (op->IsShl()) {
2464 __ Lsl(out_reg, first_reg, shift_value);
2465 } else if (op->IsShr()) {
2466 __ Asr(out_reg, first_reg, shift_value);
2467 } else {
2468 __ Lsr(out_reg, first_reg, shift_value);
2469 }
2470 }
2471 break;
2472 }
2473 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002474 Register o_h = out.AsRegisterPairHigh<Register>();
2475 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002476
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002477 Register temp = locations->GetTemp(0).AsRegister<Register>();
2478
2479 Register high = first.AsRegisterPairHigh<Register>();
2480 Register low = first.AsRegisterPairLow<Register>();
2481
2482 Register second_reg = second.AsRegister<Register>();
2483
Calin Juravle9aec02f2014-11-18 23:06:35 +00002484 if (op->IsShl()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002485 // Shift the high part
2486 __ and_(second_reg, second_reg, ShifterOperand(63));
2487 __ Lsl(o_h, high, second_reg);
2488 // Shift the low part and `or` what overflew on the high part
2489 __ rsb(temp, second_reg, ShifterOperand(32));
2490 __ Lsr(temp, low, temp);
2491 __ orr(o_h, o_h, ShifterOperand(temp));
2492 // If the shift is > 32 bits, override the high part
2493 __ subs(temp, second_reg, ShifterOperand(32));
2494 __ it(PL);
2495 __ Lsl(o_h, low, temp, false, PL);
2496 // Shift the low part
2497 __ Lsl(o_l, low, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002498 } else if (op->IsShr()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002499 // Shift the low part
2500 __ and_(second_reg, second_reg, ShifterOperand(63));
2501 __ Lsr(o_l, low, second_reg);
2502 // Shift the high part and `or` what underflew on the low part
2503 __ rsb(temp, second_reg, ShifterOperand(32));
2504 __ Lsl(temp, high, temp);
2505 __ orr(o_l, o_l, ShifterOperand(temp));
2506 // If the shift is > 32 bits, override the low part
2507 __ subs(temp, second_reg, ShifterOperand(32));
2508 __ it(PL);
2509 __ Asr(o_l, high, temp, false, PL);
2510 // Shift the high part
2511 __ Asr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002512 } else {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002513 // same as Shr except we use `Lsr`s and not `Asr`s
2514 __ and_(second_reg, second_reg, ShifterOperand(63));
2515 __ Lsr(o_l, low, second_reg);
2516 __ rsb(temp, second_reg, ShifterOperand(32));
2517 __ Lsl(temp, high, temp);
2518 __ orr(o_l, o_l, ShifterOperand(temp));
2519 __ subs(temp, second_reg, ShifterOperand(32));
2520 __ it(PL);
2521 __ Lsr(o_l, high, temp, false, PL);
2522 __ Lsr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002523 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002524 break;
2525 }
2526 default:
2527 LOG(FATAL) << "Unexpected operation type " << type;
2528 }
2529}
2530
2531void LocationsBuilderARM::VisitShl(HShl* shl) {
2532 HandleShift(shl);
2533}
2534
2535void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2536 HandleShift(shl);
2537}
2538
2539void LocationsBuilderARM::VisitShr(HShr* shr) {
2540 HandleShift(shr);
2541}
2542
2543void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2544 HandleShift(shr);
2545}
2546
2547void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2548 HandleShift(ushr);
2549}
2550
2551void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2552 HandleShift(ushr);
2553}
2554
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002555void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002556 LocationSummary* locations =
2557 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002558 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002559 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2560 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2561 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002562}
2563
2564void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2565 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002566 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002567 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002568 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2569 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002570 instruction->GetDexPc(),
2571 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002572}
2573
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002574void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2575 LocationSummary* locations =
2576 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2577 InvokeRuntimeCallingConvention calling_convention;
2578 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002579 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002580 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002581 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002582}
2583
2584void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2585 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002586 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002587 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002588 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2589 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002590 instruction->GetDexPc(),
2591 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002592}
2593
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002594void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002595 LocationSummary* locations =
2596 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002597 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2598 if (location.IsStackSlot()) {
2599 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2600 } else if (location.IsDoubleStackSlot()) {
2601 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002602 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002603 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002604}
2605
2606void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002607 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002608 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002609}
2610
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002611void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002612 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002613 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002614 locations->SetInAt(0, Location::RequiresRegister());
2615 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002616}
2617
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002618void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2619 LocationSummary* locations = not_->GetLocations();
2620 Location out = locations->Out();
2621 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002622 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002623 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002624 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002625 break;
2626
2627 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002628 __ mvn(out.AsRegisterPairLow<Register>(),
2629 ShifterOperand(in.AsRegisterPairLow<Register>()));
2630 __ mvn(out.AsRegisterPairHigh<Register>(),
2631 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002632 break;
2633
2634 default:
2635 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2636 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002637}
2638
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002639void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002640 LocationSummary* locations =
2641 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002642 switch (compare->InputAt(0)->GetType()) {
2643 case Primitive::kPrimLong: {
2644 locations->SetInAt(0, Location::RequiresRegister());
2645 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002646 // Output overlaps because it is written before doing the low comparison.
2647 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00002648 break;
2649 }
2650 case Primitive::kPrimFloat:
2651 case Primitive::kPrimDouble: {
2652 locations->SetInAt(0, Location::RequiresFpuRegister());
2653 locations->SetInAt(1, Location::RequiresFpuRegister());
2654 locations->SetOut(Location::RequiresRegister());
2655 break;
2656 }
2657 default:
2658 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2659 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002660}
2661
2662void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002663 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002664 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002665 Location left = locations->InAt(0);
2666 Location right = locations->InAt(1);
2667
2668 Label less, greater, done;
2669 Primitive::Type type = compare->InputAt(0)->GetType();
2670 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002671 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002672 __ cmp(left.AsRegisterPairHigh<Register>(),
2673 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002674 __ b(&less, LT);
2675 __ b(&greater, GT);
Calin Juravleddb7df22014-11-25 20:56:51 +00002676 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2677 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002678 __ cmp(left.AsRegisterPairLow<Register>(),
2679 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00002680 break;
2681 }
2682 case Primitive::kPrimFloat:
2683 case Primitive::kPrimDouble: {
2684 __ LoadImmediate(out, 0);
2685 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002686 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002687 } else {
2688 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2689 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2690 }
2691 __ vmstat(); // transfer FP status register to ARM APSR.
2692 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002693 break;
2694 }
2695 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002696 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002697 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002698 __ b(&done, EQ);
2699 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats.
2700
2701 __ Bind(&greater);
2702 __ LoadImmediate(out, 1);
2703 __ b(&done);
2704
2705 __ Bind(&less);
2706 __ LoadImmediate(out, -1);
2707
2708 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002709}
2710
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002711void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002712 LocationSummary* locations =
2713 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002714 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2715 locations->SetInAt(i, Location::Any());
2716 }
2717 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002718}
2719
2720void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002721 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002722 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002723}
2724
Calin Juravle52c48962014-12-16 17:02:57 +00002725void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2726 // TODO (ported from quick): revisit Arm barrier kinds
2727 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings
2728 switch (kind) {
2729 case MemBarrierKind::kAnyStore:
2730 case MemBarrierKind::kLoadAny:
2731 case MemBarrierKind::kAnyAny: {
2732 flavour = DmbOptions::ISH;
2733 break;
2734 }
2735 case MemBarrierKind::kStoreStore: {
2736 flavour = DmbOptions::ISHST;
2737 break;
2738 }
2739 default:
2740 LOG(FATAL) << "Unexpected memory barrier " << kind;
2741 }
2742 __ dmb(flavour);
2743}
2744
2745void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2746 uint32_t offset,
2747 Register out_lo,
2748 Register out_hi) {
2749 if (offset != 0) {
2750 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002751 __ add(IP, addr, ShifterOperand(out_lo));
2752 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002753 }
2754 __ ldrexd(out_lo, out_hi, addr);
2755}
2756
2757void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2758 uint32_t offset,
2759 Register value_lo,
2760 Register value_hi,
2761 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00002762 Register temp2,
2763 HInstruction* instruction) {
Calin Juravle52c48962014-12-16 17:02:57 +00002764 Label fail;
2765 if (offset != 0) {
2766 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002767 __ add(IP, addr, ShifterOperand(temp1));
2768 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002769 }
2770 __ Bind(&fail);
2771 // We need a load followed by store. (The address used in a STREX instruction must
2772 // be the same as the address in the most recently executed LDREX instruction.)
2773 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00002774 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002775 __ strexd(temp1, value_lo, value_hi, addr);
2776 __ cmp(temp1, ShifterOperand(0));
2777 __ b(&fail, NE);
2778}
2779
2780void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2781 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2782
Nicolas Geoffray39468442014-09-02 15:17:15 +01002783 LocationSummary* locations =
2784 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002785 locations->SetInAt(0, Location::RequiresRegister());
2786 locations->SetInAt(1, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002787
Calin Juravle34166012014-12-19 17:22:29 +00002788
Calin Juravle52c48962014-12-16 17:02:57 +00002789 Primitive::Type field_type = field_info.GetFieldType();
2790 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00002791 bool generate_volatile = field_info.IsVolatile()
2792 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002793 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002794 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00002795 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2796 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002797 locations->AddTemp(Location::RequiresRegister());
2798 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002799 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002800 // Arm encoding have some additional constraints for ldrexd/strexd:
2801 // - registers need to be consecutive
2802 // - the first register should be even but not R14.
2803 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2804 // enable Arm encoding.
2805 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2806
2807 locations->AddTemp(Location::RequiresRegister());
2808 locations->AddTemp(Location::RequiresRegister());
2809 if (field_type == Primitive::kPrimDouble) {
2810 // For doubles we need two more registers to copy the value.
2811 locations->AddTemp(Location::RegisterLocation(R2));
2812 locations->AddTemp(Location::RegisterLocation(R3));
2813 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002814 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002815}
2816
Calin Juravle52c48962014-12-16 17:02:57 +00002817void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
2818 const FieldInfo& field_info) {
2819 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2820
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002821 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00002822 Register base = locations->InAt(0).AsRegister<Register>();
2823 Location value = locations->InAt(1);
2824
2825 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002826 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002827 Primitive::Type field_type = field_info.GetFieldType();
2828 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2829
2830 if (is_volatile) {
2831 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2832 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002833
2834 switch (field_type) {
2835 case Primitive::kPrimBoolean:
2836 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002837 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002838 break;
2839 }
2840
2841 case Primitive::kPrimShort:
2842 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002843 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002844 break;
2845 }
2846
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002847 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002848 case Primitive::kPrimNot: {
Calin Juravle77520bc2015-01-12 18:45:46 +00002849 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002850 break;
2851 }
2852
2853 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002854 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002855 GenerateWideAtomicStore(base, offset,
2856 value.AsRegisterPairLow<Register>(),
2857 value.AsRegisterPairHigh<Register>(),
2858 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002859 locations->GetTemp(1).AsRegister<Register>(),
2860 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002861 } else {
2862 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002863 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002864 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002865 break;
2866 }
2867
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002868 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002869 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002870 break;
2871 }
2872
2873 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002874 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002875 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002876 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
2877 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
2878
2879 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
2880
2881 GenerateWideAtomicStore(base, offset,
2882 value_reg_lo,
2883 value_reg_hi,
2884 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00002885 locations->GetTemp(3).AsRegister<Register>(),
2886 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002887 } else {
2888 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00002889 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002890 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002891 break;
2892 }
2893
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002894 case Primitive::kPrimVoid:
2895 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002896 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002897 }
Calin Juravle52c48962014-12-16 17:02:57 +00002898
Calin Juravle77520bc2015-01-12 18:45:46 +00002899 // Longs and doubles are handled in the switch.
2900 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
2901 codegen_->MaybeRecordImplicitNullCheck(instruction);
2902 }
2903
2904 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2905 Register temp = locations->GetTemp(0).AsRegister<Register>();
2906 Register card = locations->GetTemp(1).AsRegister<Register>();
2907 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2908 }
2909
Calin Juravle52c48962014-12-16 17:02:57 +00002910 if (is_volatile) {
2911 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2912 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002913}
2914
Calin Juravle52c48962014-12-16 17:02:57 +00002915void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2916 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002917 LocationSummary* locations =
2918 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002919 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00002920
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002921 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00002922 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002923 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002924 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
2925 locations->SetOut(Location::RequiresRegister(),
2926 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
2927 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00002928 // Arm encoding have some additional constraints for ldrexd/strexd:
2929 // - registers need to be consecutive
2930 // - the first register should be even but not R14.
2931 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2932 // enable Arm encoding.
2933 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
2934 locations->AddTemp(Location::RequiresRegister());
2935 locations->AddTemp(Location::RequiresRegister());
2936 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002937}
2938
Calin Juravle52c48962014-12-16 17:02:57 +00002939void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
2940 const FieldInfo& field_info) {
2941 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002942
Calin Juravle52c48962014-12-16 17:02:57 +00002943 LocationSummary* locations = instruction->GetLocations();
2944 Register base = locations->InAt(0).AsRegister<Register>();
2945 Location out = locations->Out();
2946 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002947 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00002948 Primitive::Type field_type = field_info.GetFieldType();
2949 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2950
2951 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002952 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002953 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002954 break;
2955 }
2956
2957 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002958 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002959 break;
2960 }
2961
2962 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002963 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002964 break;
2965 }
2966
2967 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002968 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002969 break;
2970 }
2971
2972 case Primitive::kPrimInt:
2973 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002974 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002975 break;
2976 }
2977
2978 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00002979 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002980 GenerateWideAtomicLoad(base, offset,
2981 out.AsRegisterPairLow<Register>(),
2982 out.AsRegisterPairHigh<Register>());
2983 } else {
2984 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
2985 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002986 break;
2987 }
2988
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002989 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002990 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002991 break;
2992 }
2993
2994 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002995 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00002996 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00002997 Register lo = locations->GetTemp(0).AsRegister<Register>();
2998 Register hi = locations->GetTemp(1).AsRegister<Register>();
2999 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003000 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003001 __ vmovdrr(out_reg, lo, hi);
3002 } else {
3003 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003004 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003005 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003006 break;
3007 }
3008
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003009 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003010 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003011 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003012 }
Calin Juravle52c48962014-12-16 17:02:57 +00003013
Calin Juravle77520bc2015-01-12 18:45:46 +00003014 // Doubles are handled in the switch.
3015 if (field_type != Primitive::kPrimDouble) {
3016 codegen_->MaybeRecordImplicitNullCheck(instruction);
3017 }
3018
Calin Juravle52c48962014-12-16 17:02:57 +00003019 if (is_volatile) {
3020 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3021 }
3022}
3023
3024void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3025 HandleFieldSet(instruction, instruction->GetFieldInfo());
3026}
3027
3028void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3029 HandleFieldSet(instruction, instruction->GetFieldInfo());
3030}
3031
3032void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3033 HandleFieldGet(instruction, instruction->GetFieldInfo());
3034}
3035
3036void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3037 HandleFieldGet(instruction, instruction->GetFieldInfo());
3038}
3039
3040void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3041 HandleFieldGet(instruction, instruction->GetFieldInfo());
3042}
3043
3044void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3045 HandleFieldGet(instruction, instruction->GetFieldInfo());
3046}
3047
3048void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3049 HandleFieldSet(instruction, instruction->GetFieldInfo());
3050}
3051
3052void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3053 HandleFieldSet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003054}
3055
3056void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003057 LocationSummary* locations =
3058 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003059 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003060 if (instruction->HasUses()) {
3061 locations->SetOut(Location::SameAsFirstInput());
3062 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003063}
3064
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003065void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003066 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3067 return;
3068 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003069 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003070
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003071 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3072 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3073}
3074
3075void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003076 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003077 codegen_->AddSlowPath(slow_path);
3078
3079 LocationSummary* locations = instruction->GetLocations();
3080 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003081
Calin Juravle77520bc2015-01-12 18:45:46 +00003082 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
3083 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003084}
3085
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003086void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3087 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3088 GenerateImplicitNullCheck(instruction);
3089 } else {
3090 GenerateExplicitNullCheck(instruction);
3091 }
3092}
3093
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003094void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003095 LocationSummary* locations =
3096 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003097 locations->SetInAt(0, Location::RequiresRegister());
3098 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3099 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003100}
3101
3102void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3103 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003104 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003105 Location index = locations->InAt(1);
3106
3107 switch (instruction->GetType()) {
3108 case Primitive::kPrimBoolean: {
3109 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003110 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003111 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003112 size_t offset =
3113 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003114 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3115 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003116 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003117 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3118 }
3119 break;
3120 }
3121
3122 case Primitive::kPrimByte: {
3123 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003124 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003125 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003126 size_t offset =
3127 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003128 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3129 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003130 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003131 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3132 }
3133 break;
3134 }
3135
3136 case Primitive::kPrimShort: {
3137 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003139 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003140 size_t offset =
3141 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003142 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3143 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003144 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003145 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3146 }
3147 break;
3148 }
3149
3150 case Primitive::kPrimChar: {
3151 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003152 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003153 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003154 size_t offset =
3155 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003156 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3157 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003158 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003159 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3160 }
3161 break;
3162 }
3163
3164 case Primitive::kPrimInt:
3165 case Primitive::kPrimNot: {
3166 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3167 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003168 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003169 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003170 size_t offset =
3171 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003172 __ LoadFromOffset(kLoadWord, out, obj, offset);
3173 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003174 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003175 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3176 }
3177 break;
3178 }
3179
3180 case Primitive::kPrimLong: {
3181 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003182 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003183 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003184 size_t offset =
3185 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003186 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003187 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003188 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003189 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003190 }
3191 break;
3192 }
3193
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003194 case Primitive::kPrimFloat: {
3195 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3196 Location out = locations->Out();
3197 DCHECK(out.IsFpuRegister());
3198 if (index.IsConstant()) {
3199 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3200 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3201 } else {
3202 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3203 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3204 }
3205 break;
3206 }
3207
3208 case Primitive::kPrimDouble: {
3209 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3210 Location out = locations->Out();
3211 DCHECK(out.IsFpuRegisterPair());
3212 if (index.IsConstant()) {
3213 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3214 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3215 } else {
3216 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3217 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3218 }
3219 break;
3220 }
3221
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003222 case Primitive::kPrimVoid:
3223 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003224 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003225 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003226 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003227}
3228
3229void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003230 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003231
3232 bool needs_write_barrier =
3233 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3234 bool needs_runtime_call = instruction->NeedsTypeCheck();
3235
Nicolas Geoffray39468442014-09-02 15:17:15 +01003236 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003237 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3238 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003239 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003240 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3241 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3242 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003243 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003244 locations->SetInAt(0, Location::RequiresRegister());
3245 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3246 locations->SetInAt(2, Location::RequiresRegister());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003247
3248 if (needs_write_barrier) {
3249 // Temporary registers for the write barrier.
3250 locations->AddTemp(Location::RequiresRegister());
3251 locations->AddTemp(Location::RequiresRegister());
3252 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003253 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003254}
3255
3256void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3257 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003258 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003259 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003260 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003261 bool needs_runtime_call = locations->WillCall();
3262 bool needs_write_barrier =
3263 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003264
3265 switch (value_type) {
3266 case Primitive::kPrimBoolean:
3267 case Primitive::kPrimByte: {
3268 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003269 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003270 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003271 size_t offset =
3272 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003273 __ StoreToOffset(kStoreByte, value, obj, offset);
3274 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003275 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003276 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3277 }
3278 break;
3279 }
3280
3281 case Primitive::kPrimShort:
3282 case Primitive::kPrimChar: {
3283 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003284 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003285 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003286 size_t offset =
3287 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003288 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3289 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003290 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003291 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3292 }
3293 break;
3294 }
3295
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003296 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003297 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003298 if (!needs_runtime_call) {
3299 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003300 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003301 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003302 size_t offset =
3303 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003304 __ StoreToOffset(kStoreWord, value, obj, offset);
3305 } else {
3306 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003307 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003308 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3309 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003310 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003311 if (needs_write_barrier) {
3312 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003313 Register temp = locations->GetTemp(0).AsRegister<Register>();
3314 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003315 codegen_->MarkGCCard(temp, card, obj, value);
3316 }
3317 } else {
3318 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003319 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3320 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003321 instruction->GetDexPc(),
3322 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003323 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003324 break;
3325 }
3326
3327 case Primitive::kPrimLong: {
3328 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003329 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003330 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003331 size_t offset =
3332 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003333 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003334 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003335 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003336 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003337 }
3338 break;
3339 }
3340
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003341 case Primitive::kPrimFloat: {
3342 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3343 Location value = locations->InAt(2);
3344 DCHECK(value.IsFpuRegister());
3345 if (index.IsConstant()) {
3346 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3347 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3348 } else {
3349 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3350 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3351 }
3352 break;
3353 }
3354
3355 case Primitive::kPrimDouble: {
3356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3357 Location value = locations->InAt(2);
3358 DCHECK(value.IsFpuRegisterPair());
3359 if (index.IsConstant()) {
3360 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3361 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3362 } else {
3363 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3364 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3365 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003366
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003367 break;
3368 }
3369
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003370 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003371 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003372 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003373 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003374
3375 // Ints and objects are handled in the switch.
3376 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3377 codegen_->MaybeRecordImplicitNullCheck(instruction);
3378 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003379}
3380
3381void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003382 LocationSummary* locations =
3383 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003384 locations->SetInAt(0, Location::RequiresRegister());
3385 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003386}
3387
3388void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3389 LocationSummary* locations = instruction->GetLocations();
3390 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003391 Register obj = locations->InAt(0).AsRegister<Register>();
3392 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003393 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003394 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003395}
3396
3397void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003398 LocationSummary* locations =
3399 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003400 locations->SetInAt(0, Location::RequiresRegister());
3401 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003402 if (instruction->HasUses()) {
3403 locations->SetOut(Location::SameAsFirstInput());
3404 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003405}
3406
3407void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3408 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003409 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003410 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003411 codegen_->AddSlowPath(slow_path);
3412
Roland Levillain271ab9c2014-11-27 15:23:57 +00003413 Register index = locations->InAt(0).AsRegister<Register>();
3414 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003415
3416 __ cmp(index, ShifterOperand(length));
3417 __ b(slow_path->GetEntryLabel(), CS);
3418}
3419
3420void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
3421 Label is_null;
3422 __ CompareAndBranchIfZero(value, &is_null);
3423 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3424 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3425 __ strb(card, Address(card, temp));
3426 __ Bind(&is_null);
3427}
3428
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003429void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3430 temp->SetLocations(nullptr);
3431}
3432
3433void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3434 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003435 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003436}
3437
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003438void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003439 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003440 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003441}
3442
3443void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003444 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3445}
3446
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003447void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3448 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3449}
3450
3451void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003452 HBasicBlock* block = instruction->GetBlock();
3453 if (block->GetLoopInformation() != nullptr) {
3454 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3455 // The back edge will generate the suspend check.
3456 return;
3457 }
3458 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3459 // The goto will generate the suspend check.
3460 return;
3461 }
3462 GenerateSuspendCheck(instruction, nullptr);
3463}
3464
3465void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3466 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003467 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003468 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003469 codegen_->AddSlowPath(slow_path);
3470
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003471 __ LoadFromOffset(
3472 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3473 __ cmp(IP, ShifterOperand(0));
3474 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003475 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003476 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003477 __ Bind(slow_path->GetReturnLabel());
3478 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003479 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003480 __ b(slow_path->GetEntryLabel());
3481 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003482}
3483
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003484ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3485 return codegen_->GetAssembler();
3486}
3487
3488void ParallelMoveResolverARM::EmitMove(size_t index) {
3489 MoveOperands* move = moves_.Get(index);
3490 Location source = move->GetSource();
3491 Location destination = move->GetDestination();
3492
3493 if (source.IsRegister()) {
3494 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003495 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003496 } else {
3497 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003498 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003499 SP, destination.GetStackIndex());
3500 }
3501 } else if (source.IsStackSlot()) {
3502 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003503 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003504 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003505 } else if (destination.IsFpuRegister()) {
3506 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003507 } else {
3508 DCHECK(destination.IsStackSlot());
3509 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3510 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3511 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003512 } else if (source.IsFpuRegister()) {
3513 if (destination.IsFpuRegister()) {
3514 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003515 } else {
3516 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003517 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3518 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003519 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003520 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003521 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
3522 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003523 } else if (destination.IsRegisterPair()) {
3524 DCHECK(ExpectedPairLayout(destination));
3525 __ LoadFromOffset(
3526 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
3527 } else {
3528 DCHECK(destination.IsFpuRegisterPair()) << destination;
3529 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3530 SP,
3531 source.GetStackIndex());
3532 }
3533 } else if (source.IsRegisterPair()) {
3534 if (destination.IsRegisterPair()) {
3535 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
3536 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
3537 } else {
3538 DCHECK(destination.IsDoubleStackSlot()) << destination;
3539 DCHECK(ExpectedPairLayout(source));
3540 __ StoreToOffset(
3541 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
3542 }
3543 } else if (source.IsFpuRegisterPair()) {
3544 if (destination.IsFpuRegisterPair()) {
3545 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3546 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
3547 } else {
3548 DCHECK(destination.IsDoubleStackSlot()) << destination;
3549 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
3550 SP,
3551 destination.GetStackIndex());
3552 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003553 } else {
3554 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003555 HConstant* constant = source.GetConstant();
3556 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3557 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003558 if (destination.IsRegister()) {
3559 __ LoadImmediate(destination.AsRegister<Register>(), value);
3560 } else {
3561 DCHECK(destination.IsStackSlot());
3562 __ LoadImmediate(IP, value);
3563 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3564 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003565 } else if (constant->IsLongConstant()) {
3566 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003567 if (destination.IsRegisterPair()) {
3568 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
3569 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003570 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003571 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003572 __ LoadImmediate(IP, Low32Bits(value));
3573 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3574 __ LoadImmediate(IP, High32Bits(value));
3575 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3576 }
3577 } else if (constant->IsDoubleConstant()) {
3578 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003579 if (destination.IsFpuRegisterPair()) {
3580 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003581 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003582 DCHECK(destination.IsDoubleStackSlot()) << destination;
3583 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003584 __ LoadImmediate(IP, Low32Bits(int_value));
3585 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3586 __ LoadImmediate(IP, High32Bits(int_value));
3587 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3588 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003589 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003590 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003591 float value = constant->AsFloatConstant()->GetValue();
3592 if (destination.IsFpuRegister()) {
3593 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3594 } else {
3595 DCHECK(destination.IsStackSlot());
3596 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3597 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3598 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003599 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003600 }
3601}
3602
3603void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3604 __ Mov(IP, reg);
3605 __ LoadFromOffset(kLoadWord, reg, SP, mem);
3606 __ StoreToOffset(kStoreWord, IP, SP, mem);
3607}
3608
3609void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3610 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3611 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3612 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3613 SP, mem1 + stack_offset);
3614 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3615 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3616 SP, mem2 + stack_offset);
3617 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3618}
3619
3620void ParallelMoveResolverARM::EmitSwap(size_t index) {
3621 MoveOperands* move = moves_.Get(index);
3622 Location source = move->GetSource();
3623 Location destination = move->GetDestination();
3624
3625 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003626 DCHECK_NE(source.AsRegister<Register>(), IP);
3627 DCHECK_NE(destination.AsRegister<Register>(), IP);
3628 __ Mov(IP, source.AsRegister<Register>());
3629 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3630 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003631 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003632 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003633 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003634 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003635 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3636 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003637 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003638 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003639 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003640 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003641 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003642 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003643 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003644 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003645 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
3646 destination.AsRegisterPairHigh<Register>(),
3647 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003648 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003649 Register low_reg = source.IsRegisterPair()
3650 ? source.AsRegisterPairLow<Register>()
3651 : destination.AsRegisterPairLow<Register>();
3652 int mem = source.IsRegisterPair()
3653 ? destination.GetStackIndex()
3654 : source.GetStackIndex();
3655 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003656 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003657 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003658 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003659 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003660 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
3661 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003662 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003663 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003664 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003665 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
3666 DRegister reg = source.IsFpuRegisterPair()
3667 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
3668 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3669 int mem = source.IsFpuRegisterPair()
3670 ? destination.GetStackIndex()
3671 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003672 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003673 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003674 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003675 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3676 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3677 : destination.AsFpuRegister<SRegister>();
3678 int mem = source.IsFpuRegister()
3679 ? destination.GetStackIndex()
3680 : source.GetStackIndex();
3681
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003682 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003683 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003684 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003685 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003686 Exchange(source.GetStackIndex(), destination.GetStackIndex());
3687 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003688 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003689 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003690 }
3691}
3692
3693void ParallelMoveResolverARM::SpillScratch(int reg) {
3694 __ Push(static_cast<Register>(reg));
3695}
3696
3697void ParallelMoveResolverARM::RestoreScratch(int reg) {
3698 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003699}
3700
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003701void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003702 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3703 ? LocationSummary::kCallOnSlowPath
3704 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003705 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003706 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003707 locations->SetOut(Location::RequiresRegister());
3708}
3709
3710void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003711 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003712 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003713 DCHECK(!cls->CanCallRuntime());
3714 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003715 codegen_->LoadCurrentMethod(out);
3716 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3717 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003718 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003719 codegen_->LoadCurrentMethod(out);
3720 __ LoadFromOffset(
3721 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
3722 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003723
3724 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3725 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3726 codegen_->AddSlowPath(slow_path);
3727 __ cmp(out, ShifterOperand(0));
3728 __ b(slow_path->GetEntryLabel(), EQ);
3729 if (cls->MustGenerateClinitCheck()) {
3730 GenerateClassInitializationCheck(slow_path, out);
3731 } else {
3732 __ Bind(slow_path->GetExitLabel());
3733 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003734 }
3735}
3736
3737void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3738 LocationSummary* locations =
3739 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3740 locations->SetInAt(0, Location::RequiresRegister());
3741 if (check->HasUses()) {
3742 locations->SetOut(Location::SameAsFirstInput());
3743 }
3744}
3745
3746void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003747 // We assume the class is not null.
3748 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3749 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003750 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003751 GenerateClassInitializationCheck(slow_path,
3752 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003753}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003754
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003755void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3756 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003757 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3758 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3759 __ b(slow_path->GetEntryLabel(), LT);
3760 // Even if the initialized flag is set, we may be in a situation where caches are not synced
3761 // properly. Therefore, we do a memory fence.
3762 __ dmb(ISH);
3763 __ Bind(slow_path->GetExitLabel());
3764}
3765
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003766void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3767 LocationSummary* locations =
3768 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3769 locations->SetOut(Location::RequiresRegister());
3770}
3771
3772void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
3773 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
3774 codegen_->AddSlowPath(slow_path);
3775
Roland Levillain271ab9c2014-11-27 15:23:57 +00003776 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003777 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003778 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
3779 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003780 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
3781 __ cmp(out, ShifterOperand(0));
3782 __ b(slow_path->GetEntryLabel(), EQ);
3783 __ Bind(slow_path->GetExitLabel());
3784}
3785
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003786void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
3787 LocationSummary* locations =
3788 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3789 locations->SetOut(Location::RequiresRegister());
3790}
3791
3792void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003793 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003794 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
3795 __ LoadFromOffset(kLoadWord, out, TR, offset);
3796 __ LoadImmediate(IP, 0);
3797 __ StoreToOffset(kStoreWord, IP, TR, offset);
3798}
3799
3800void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
3801 LocationSummary* locations =
3802 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3803 InvokeRuntimeCallingConvention calling_convention;
3804 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3805}
3806
3807void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
3808 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003809 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003810}
3811
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003812void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003813 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3814 ? LocationSummary::kNoCall
3815 : LocationSummary::kCallOnSlowPath;
3816 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3817 locations->SetInAt(0, Location::RequiresRegister());
3818 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003819 // The out register is used as a temporary, so it overlaps with the inputs.
3820 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003821}
3822
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003823void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003824 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003825 Register obj = locations->InAt(0).AsRegister<Register>();
3826 Register cls = locations->InAt(1).AsRegister<Register>();
3827 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003828 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3829 Label done, zero;
3830 SlowPathCodeARM* slow_path = nullptr;
3831
3832 // Return 0 if `obj` is null.
3833 // TODO: avoid this check if we know obj is not null.
3834 __ cmp(obj, ShifterOperand(0));
3835 __ b(&zero, EQ);
3836 // Compare the class of `obj` with `cls`.
3837 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
3838 __ cmp(out, ShifterOperand(cls));
3839 if (instruction->IsClassFinal()) {
3840 // Classes must be equal for the instanceof to succeed.
3841 __ b(&zero, NE);
3842 __ LoadImmediate(out, 1);
3843 __ b(&done);
3844 } else {
3845 // If the classes are not equal, we go into a slow path.
3846 DCHECK(locations->OnlyCallsOnSlowPath());
3847 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003848 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003849 codegen_->AddSlowPath(slow_path);
3850 __ b(slow_path->GetEntryLabel(), NE);
3851 __ LoadImmediate(out, 1);
3852 __ b(&done);
3853 }
3854 __ Bind(&zero);
3855 __ LoadImmediate(out, 0);
3856 if (slow_path != nullptr) {
3857 __ Bind(slow_path->GetExitLabel());
3858 }
3859 __ Bind(&done);
3860}
3861
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003862void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
3863 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3864 instruction, LocationSummary::kCallOnSlowPath);
3865 locations->SetInAt(0, Location::RequiresRegister());
3866 locations->SetInAt(1, Location::RequiresRegister());
3867 locations->AddTemp(Location::RequiresRegister());
3868}
3869
3870void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
3871 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003872 Register obj = locations->InAt(0).AsRegister<Register>();
3873 Register cls = locations->InAt(1).AsRegister<Register>();
3874 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003875 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3876
3877 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
3878 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3879 codegen_->AddSlowPath(slow_path);
3880
3881 // TODO: avoid this check if we know obj is not null.
3882 __ cmp(obj, ShifterOperand(0));
3883 __ b(slow_path->GetExitLabel(), EQ);
3884 // Compare the class of `obj` with `cls`.
3885 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
3886 __ cmp(temp, ShifterOperand(cls));
3887 __ b(slow_path->GetEntryLabel(), NE);
3888 __ Bind(slow_path->GetExitLabel());
3889}
3890
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003891void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3892 LocationSummary* locations =
3893 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3894 InvokeRuntimeCallingConvention calling_convention;
3895 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3896}
3897
3898void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
3899 codegen_->InvokeRuntime(instruction->IsEnter()
3900 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
3901 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003902 instruction->GetDexPc(),
3903 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003904}
3905
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003906void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3907void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3908void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3909
3910void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3911 LocationSummary* locations =
3912 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3913 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3914 || instruction->GetResultType() == Primitive::kPrimLong);
3915 locations->SetInAt(0, Location::RequiresRegister());
3916 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003917 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003918}
3919
3920void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
3921 HandleBitwiseOperation(instruction);
3922}
3923
3924void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
3925 HandleBitwiseOperation(instruction);
3926}
3927
3928void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
3929 HandleBitwiseOperation(instruction);
3930}
3931
3932void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
3933 LocationSummary* locations = instruction->GetLocations();
3934
3935 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003936 Register first = locations->InAt(0).AsRegister<Register>();
3937 Register second = locations->InAt(1).AsRegister<Register>();
3938 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003939 if (instruction->IsAnd()) {
3940 __ and_(out, first, ShifterOperand(second));
3941 } else if (instruction->IsOr()) {
3942 __ orr(out, first, ShifterOperand(second));
3943 } else {
3944 DCHECK(instruction->IsXor());
3945 __ eor(out, first, ShifterOperand(second));
3946 }
3947 } else {
3948 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3949 Location first = locations->InAt(0);
3950 Location second = locations->InAt(1);
3951 Location out = locations->Out();
3952 if (instruction->IsAnd()) {
3953 __ and_(out.AsRegisterPairLow<Register>(),
3954 first.AsRegisterPairLow<Register>(),
3955 ShifterOperand(second.AsRegisterPairLow<Register>()));
3956 __ and_(out.AsRegisterPairHigh<Register>(),
3957 first.AsRegisterPairHigh<Register>(),
3958 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3959 } else if (instruction->IsOr()) {
3960 __ orr(out.AsRegisterPairLow<Register>(),
3961 first.AsRegisterPairLow<Register>(),
3962 ShifterOperand(second.AsRegisterPairLow<Register>()));
3963 __ orr(out.AsRegisterPairHigh<Register>(),
3964 first.AsRegisterPairHigh<Register>(),
3965 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3966 } else {
3967 DCHECK(instruction->IsXor());
3968 __ eor(out.AsRegisterPairLow<Register>(),
3969 first.AsRegisterPairLow<Register>(),
3970 ShifterOperand(second.AsRegisterPairLow<Register>()));
3971 __ eor(out.AsRegisterPairHigh<Register>(),
3972 first.AsRegisterPairHigh<Register>(),
3973 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3974 }
3975 }
3976}
3977
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003978void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
3979 DCHECK_EQ(temp, kArtMethodRegister);
3980
3981 // TODO: Implement all kinds of calls:
3982 // 1) boot -> boot
3983 // 2) app -> boot
3984 // 3) app -> app
3985 //
3986 // Currently we implement the app -> app logic, which looks up in the resolve cache.
3987
3988 // temp = method;
3989 LoadCurrentMethod(temp);
3990 if (!invoke->IsRecursive()) {
3991 // temp = temp->dex_cache_resolved_methods_;
3992 __ LoadFromOffset(
3993 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
3994 // temp = temp[index_in_cache]
3995 __ LoadFromOffset(
3996 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
3997 // LR = temp[offset_of_quick_compiled_code]
3998 __ LoadFromOffset(kLoadWord, LR, temp,
3999 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4000 kArmWordSize).Int32Value());
4001 // LR()
4002 __ blx(LR);
4003 } else {
4004 __ bl(GetFrameEntryLabel());
4005 }
4006
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004007 DCHECK(!IsLeafMethod());
4008}
4009
Calin Juravleb1498f62015-02-16 13:13:29 +00004010void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4011 // Nothing to do, this should be removed during prepare for register allocator.
4012 UNUSED(instruction);
4013 LOG(FATAL) << "Unreachable";
4014}
4015
4016void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4017 // Nothing to do, this should be removed during prepare for register allocator.
4018 UNUSED(instruction);
4019 LOG(FATAL) << "Unreachable";
4020}
4021
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004022} // namespace arm
4023} // namespace art