blob: 62026f31abfc127daca593fa0b7e11f6ab815eef [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"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "art_method.h"
Zheng Xuc6667102015-05-15 16:08:45 +080021#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000022#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070023#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010024#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080025#include "intrinsics.h"
26#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070027#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070028#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070029#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "utils/arm/assembler_arm.h"
31#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000032#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010033#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010036
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000037namespace arm {
38
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000039static bool ExpectedPairLayout(Location location) {
40 // We expected this for both core and fpu register pairs.
41 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
42}
43
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010044static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010045static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010046
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000047// We unconditionally allocate R5 to ensure we can do long operations
48// with baseline.
49static constexpr Register kCoreSavedRegisterForBaseline = R5;
50static constexpr Register kCoreCalleeSaves[] =
51 { R5, R6, R7, R8, R10, R11, PC };
52static constexpr SRegister kFpuCalleeSaves[] =
53 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010054
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000055// D31 cannot be split into two S registers, and the register allocator only works on
56// S registers. Therefore there is no need to block it.
57static constexpr DRegister DTMP = D31;
58
Roland Levillain62a46b22015-06-01 18:24:13 +010059#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010060#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010062class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010064 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Alexandre Rames67555f72014-11-18 10:55:16 +000066 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010067 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010069 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000070 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071 }
72
Alexandre Rames8158f282015-08-07 10:26:17 +010073 bool IsFatal() const OVERRIDE { return true; }
74
Alexandre Rames9931f312015-06-19 14:47:01 +010075 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
76
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010078 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010079 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
80};
81
Calin Juravled0d48522014-11-04 16:40:20 +000082class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
83 public:
84 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
85
Alexandre Rames67555f72014-11-18 10:55:16 +000086 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000087 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
88 __ Bind(GetEntryLabel());
89 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000090 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +000091 }
92
Alexandre Rames8158f282015-08-07 10:26:17 +010093 bool IsFatal() const OVERRIDE { return true; }
94
Alexandre Rames9931f312015-06-19 14:47:01 +010095 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
96
Calin Juravled0d48522014-11-04 16:40:20 +000097 private:
98 HDivZeroCheck* const instruction_;
99 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
100};
101
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100102class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000103 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000104 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100105 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000106
Alexandre Rames67555f72014-11-18 10:55:16 +0000107 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100108 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000109 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000110 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100111 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000112 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000113 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100114 if (successor_ == nullptr) {
115 __ b(GetReturnLabel());
116 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100117 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100118 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000119 }
120
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100121 Label* GetReturnLabel() {
122 DCHECK(successor_ == nullptr);
123 return &return_label_;
124 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000125
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100126 HBasicBlock* GetSuccessor() const {
127 return successor_;
128 }
129
Alexandre Rames9931f312015-06-19 14:47:01 +0100130 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
131
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 private:
133 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 // If not null, the block to branch to after the suspend check.
135 HBasicBlock* const successor_;
136
137 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 Label return_label_;
139
140 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
141};
142
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100143class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100144 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100145 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
146 Location index_location,
147 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100148 : instruction_(instruction),
149 index_location_(index_location),
150 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100151
Alexandre Rames67555f72014-11-18 10:55:16 +0000152 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100153 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100154 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000155 // We're moving two locations to locations that could overlap, so we need a parallel
156 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100157 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000158 codegen->EmitParallelMoves(
159 index_location_,
160 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100161 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000162 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100163 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
164 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100165 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000166 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100167 }
168
Alexandre Rames8158f282015-08-07 10:26:17 +0100169 bool IsFatal() const OVERRIDE { return true; }
170
Alexandre Rames9931f312015-06-19 14:47:01 +0100171 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
172
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100173 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100174 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100175 const Location index_location_;
176 const Location length_location_;
177
178 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
179};
180
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000181class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100182 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000183 LoadClassSlowPathARM(HLoadClass* cls,
184 HInstruction* at,
185 uint32_t dex_pc,
186 bool do_clinit)
187 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
188 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
189 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190
Alexandre Rames67555f72014-11-18 10:55:16 +0000191 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000192 LocationSummary* locations = at_->GetLocations();
193
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100194 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
195 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000196 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100197
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100198 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000199 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000200 int32_t entry_point_offset = do_clinit_
201 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
202 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000203 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204
205 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000206 Location out = locations->Out();
207 if (out.IsValid()) {
208 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
210 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000211 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 __ b(GetExitLabel());
213 }
214
Alexandre Rames9931f312015-06-19 14:47:01 +0100215 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
216
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100217 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000218 // The class this slow path will load.
219 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100220
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000221 // The instruction where this slow path is happening.
222 // (Might be the load class or an initialization check).
223 HInstruction* const at_;
224
225 // The dex PC of `at_`.
226 const uint32_t dex_pc_;
227
228 // Whether to initialize the class.
229 const bool do_clinit_;
230
231 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100232};
233
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000234class LoadStringSlowPathARM : public SlowPathCodeARM {
235 public:
236 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
237
Alexandre Rames67555f72014-11-18 10:55:16 +0000238 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000239 LocationSummary* locations = instruction_->GetLocations();
240 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
241
242 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
243 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000244 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000245
246 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800247 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000248 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000249 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000250 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
251
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000252 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000253 __ b(GetExitLabel());
254 }
255
Alexandre Rames9931f312015-06-19 14:47:01 +0100256 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
257
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000258 private:
259 HLoadString* const instruction_;
260
261 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
262};
263
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000264class TypeCheckSlowPathARM : public SlowPathCodeARM {
265 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000266 TypeCheckSlowPathARM(HInstruction* instruction,
267 Location class_to_check,
268 Location object_class,
269 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000270 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000271 class_to_check_(class_to_check),
272 object_class_(object_class),
273 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000274
Alexandre Rames67555f72014-11-18 10:55:16 +0000275 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000277 DCHECK(instruction_->IsCheckCast()
278 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000279
280 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
281 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000282 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000283
284 // We're moving two locations to locations that could overlap, so we need a parallel
285 // move resolver.
286 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000287 codegen->EmitParallelMoves(
288 class_to_check_,
289 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100290 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000291 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100292 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
293 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000295 if (instruction_->IsInstanceOf()) {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000296 arm_codegen->InvokeRuntime(
297 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000298 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
299 } else {
300 DCHECK(instruction_->IsCheckCast());
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000301 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000302 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000303
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000304 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000305 __ b(GetExitLabel());
306 }
307
Alexandre Rames9931f312015-06-19 14:47:01 +0100308 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
309
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000311 HInstruction* const instruction_;
312 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000314 uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000315
316 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
317};
318
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700319class DeoptimizationSlowPathARM : public SlowPathCodeARM {
320 public:
321 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
322 : instruction_(instruction) {}
323
324 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
325 __ Bind(GetEntryLabel());
326 SaveLiveRegisters(codegen, instruction_->GetLocations());
327 DCHECK(instruction_->IsDeoptimize());
328 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
329 uint32_t dex_pc = deoptimize->GetDexPc();
330 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
331 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
332 }
333
Alexandre Rames9931f312015-06-19 14:47:01 +0100334 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
335
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700336 private:
337 HInstruction* const instruction_;
338 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
339};
340
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000341#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100342#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700343
Roland Levillain4fa13f62015-07-06 18:11:54 +0100344inline Condition ARMSignedOrFPCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700345 switch (cond) {
346 case kCondEQ: return EQ;
347 case kCondNE: return NE;
348 case kCondLT: return LT;
349 case kCondLE: return LE;
350 case kCondGT: return GT;
351 case kCondGE: return GE;
Dave Allison20dfc792014-06-16 20:44:29 -0700352 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100353 LOG(FATAL) << "Unreachable";
354 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700355}
356
Roland Levillain4fa13f62015-07-06 18:11:54 +0100357inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700358 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100359 case kCondEQ: return EQ;
360 case kCondNE: return NE;
361 case kCondLT: return LO;
362 case kCondLE: return LS;
363 case kCondGT: return HI;
364 case kCondGE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700365 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100366 LOG(FATAL) << "Unreachable";
367 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700368}
369
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100370void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100371 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100372}
373
374void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100375 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100376}
377
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100378size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
379 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
380 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100381}
382
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100383size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
384 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
385 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100386}
387
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000388size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
389 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
390 return kArmWordSize;
391}
392
393size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
394 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
395 return kArmWordSize;
396}
397
Calin Juravle34166012014-12-19 17:22:29 +0000398CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000399 const ArmInstructionSetFeatures& isa_features,
400 const CompilerOptions& compiler_options)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000401 : CodeGenerator(graph,
402 kNumberOfCoreRegisters,
403 kNumberOfSRegisters,
404 kNumberOfRegisterPairs,
405 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
406 arraysize(kCoreCalleeSaves)),
407 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
408 arraysize(kFpuCalleeSaves)),
409 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100410 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100411 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100412 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100413 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000414 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000415 isa_features_(isa_features),
416 method_patches_(MethodReferenceComparator(), graph->GetArena()->Adapter()),
417 call_patches_(MethodReferenceComparator(), graph->GetArena()->Adapter()),
418 relative_call_patches_(graph->GetArena()->Adapter()) {
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000419 // Save the PC register to mimic Quick.
420 AddAllocatedRegister(Location::RegisterLocation(PC));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100421}
422
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000423void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
424 // Ensure that we fix up branches and literal loads and emit the literal pool.
425 __ FinalizeCode();
426
427 // Adjust native pc offsets in stack maps.
428 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
429 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
430 uint32_t new_position = __ GetAdjustedPosition(old_position);
431 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
432 }
433 // Adjust native pc offsets of block labels.
434 for (size_t block_idx = 0u, end = block_order_->Size(); block_idx != end; ++block_idx) {
435 HBasicBlock* block = block_order_->Get(block_idx);
436 // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
437 // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
438 DCHECK_LT(static_cast<size_t>(block->GetBlockId()), block_labels_.Size());
439 Label* block_label = &block_labels_.GetRawStorage()[block->GetBlockId()];
David Brazdilfc6a86a2015-06-26 10:33:45 +0000440 DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000441 if (block_label->IsBound()) {
442 __ AdjustLabelPosition(block_label);
443 }
444 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100445 // Adjust pc offsets for the disassembly information.
446 if (disasm_info_ != nullptr) {
447 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
448 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
449 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
450 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
451 it.second.start = __ GetAdjustedPosition(it.second.start);
452 it.second.end = __ GetAdjustedPosition(it.second.end);
453 }
454 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
455 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
456 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
457 }
458 }
Vladimir Marko58155012015-08-19 12:49:41 +0000459 // Adjust pc offsets for relative call patches.
460 for (MethodPatchInfo<Label>& info : relative_call_patches_) {
461 __ AdjustLabelPosition(&info.label);
462 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000463
464 CodeGenerator::Finalize(allocator);
465}
466
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100467Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100468 switch (type) {
469 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100470 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100471 ArmManagedRegister pair =
472 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100473 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
474 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
475
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100476 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
477 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100478 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100479 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100480 }
481
482 case Primitive::kPrimByte:
483 case Primitive::kPrimBoolean:
484 case Primitive::kPrimChar:
485 case Primitive::kPrimShort:
486 case Primitive::kPrimInt:
487 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100488 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100489 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100490 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
491 ArmManagedRegister current =
492 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
493 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100494 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100495 }
496 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100497 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100498 }
499
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000500 case Primitive::kPrimFloat: {
501 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100502 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100503 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100504
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000505 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000506 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
507 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000508 return Location::FpuRegisterPairLocation(reg, reg + 1);
509 }
510
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100511 case Primitive::kPrimVoid:
512 LOG(FATAL) << "Unreachable type " << type;
513 }
514
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100515 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100516}
517
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000518void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100519 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100520 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100521
522 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100523 blocked_core_registers_[SP] = true;
524 blocked_core_registers_[LR] = true;
525 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100526
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100527 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100528 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100529
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100530 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100531 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100532
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000533 if (is_baseline) {
534 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
535 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
536 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000537
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000538 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
539
540 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
541 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
542 }
543 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100544
545 UpdateBlockedPairRegisters();
546}
547
548void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
549 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
550 ArmManagedRegister current =
551 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
552 if (blocked_core_registers_[current.AsRegisterPairLow()]
553 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
554 blocked_register_pairs_[i] = true;
555 }
556 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100557}
558
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100559InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
560 : HGraphVisitor(graph),
561 assembler_(codegen->GetAssembler()),
562 codegen_(codegen) {}
563
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000564void CodeGeneratorARM::ComputeSpillMask() {
565 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000566 // Save one extra register for baseline. Note that on thumb2, there is no easy
567 // instruction to restore just the PC, so this actually helps both baseline
568 // and non-baseline to save and restore at least two registers at entry and exit.
569 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000570 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
571 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
572 // We use vpush and vpop for saving and restoring floating point registers, which take
573 // a SRegister and the number of registers to save/restore after that SRegister. We
574 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
575 // but in the range.
576 if (fpu_spill_mask_ != 0) {
577 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
578 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
579 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
580 fpu_spill_mask_ |= (1 << i);
581 }
582 }
583}
584
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100585static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100586 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100587}
588
589static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100590 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100591}
592
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000593void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000594 bool skip_overflow_check =
595 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000596 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000597 __ Bind(&frame_entry_label_);
598
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000599 if (HasEmptyFrame()) {
600 return;
601 }
602
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100603 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000604 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
605 __ LoadFromOffset(kLoadWord, IP, IP, 0);
606 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100607 }
608
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000609 // PC is in the list of callee-save to mimic Quick, but we need to push
610 // LR at entry instead.
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100611 uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR;
612 __ PushList(push_mask);
613 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100614 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, push_mask, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000615 if (fpu_spill_mask_ != 0) {
616 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
617 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100618 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100619 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000620 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100621 int adjust = GetFrameSize() - FrameEntrySpillSize();
622 __ AddConstant(SP, -adjust);
623 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100624 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000625}
626
627void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000628 if (HasEmptyFrame()) {
629 __ bx(LR);
630 return;
631 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100632 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100633 int adjust = GetFrameSize() - FrameEntrySpillSize();
634 __ AddConstant(SP, adjust);
635 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000636 if (fpu_spill_mask_ != 0) {
637 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
638 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100639 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
640 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000641 }
642 __ PopList(core_spill_mask_);
David Srbeckyc34dc932015-04-12 09:27:43 +0100643 __ cfi().RestoreState();
644 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000645}
646
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100647void CodeGeneratorARM::Bind(HBasicBlock* block) {
648 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000649}
650
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100651Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
652 switch (load->GetType()) {
653 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100654 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100655 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100656
657 case Primitive::kPrimInt:
658 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100659 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100660 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100661
662 case Primitive::kPrimBoolean:
663 case Primitive::kPrimByte:
664 case Primitive::kPrimChar:
665 case Primitive::kPrimShort:
666 case Primitive::kPrimVoid:
667 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700668 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100669 }
670
671 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700672 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100673}
674
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100675Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100676 switch (type) {
677 case Primitive::kPrimBoolean:
678 case Primitive::kPrimByte:
679 case Primitive::kPrimChar:
680 case Primitive::kPrimShort:
681 case Primitive::kPrimInt:
682 case Primitive::kPrimNot: {
683 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000684 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100685 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100686 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100687 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000688 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100689 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100690 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100691
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000692 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100693 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000694 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100695 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000696 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100697 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000698 if (calling_convention.GetRegisterAt(index) == R1) {
699 // Skip R1, and use R2_R3 instead.
700 gp_index_++;
701 index++;
702 }
703 }
704 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
705 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000706 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000707 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000708 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100709 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000710 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
711 }
712 }
713
714 case Primitive::kPrimFloat: {
715 uint32_t stack_index = stack_index_++;
716 if (float_index_ % 2 == 0) {
717 float_index_ = std::max(double_index_, float_index_);
718 }
719 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
720 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
721 } else {
722 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
723 }
724 }
725
726 case Primitive::kPrimDouble: {
727 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
728 uint32_t stack_index = stack_index_;
729 stack_index_ += 2;
730 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
731 uint32_t index = double_index_;
732 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000733 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000734 calling_convention.GetFpuRegisterAt(index),
735 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000736 DCHECK(ExpectedPairLayout(result));
737 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000738 } else {
739 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100740 }
741 }
742
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100743 case Primitive::kPrimVoid:
744 LOG(FATAL) << "Unexpected parameter type " << type;
745 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100746 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100747 return Location();
748}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100749
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100750Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000751 switch (type) {
752 case Primitive::kPrimBoolean:
753 case Primitive::kPrimByte:
754 case Primitive::kPrimChar:
755 case Primitive::kPrimShort:
756 case Primitive::kPrimInt:
757 case Primitive::kPrimNot: {
758 return Location::RegisterLocation(R0);
759 }
760
761 case Primitive::kPrimFloat: {
762 return Location::FpuRegisterLocation(S0);
763 }
764
765 case Primitive::kPrimLong: {
766 return Location::RegisterPairLocation(R0, R1);
767 }
768
769 case Primitive::kPrimDouble: {
770 return Location::FpuRegisterPairLocation(S0, S1);
771 }
772
773 case Primitive::kPrimVoid:
774 return Location();
775 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100776
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000777 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000778}
779
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100780Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
781 return Location::RegisterLocation(kMethodRegisterArgument);
782}
783
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100784void CodeGeneratorARM::Move32(Location destination, Location source) {
785 if (source.Equals(destination)) {
786 return;
787 }
788 if (destination.IsRegister()) {
789 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000790 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100791 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000792 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100793 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000794 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100795 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100796 } else if (destination.IsFpuRegister()) {
797 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000798 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100799 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000800 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100801 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000802 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100803 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100804 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000805 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100806 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000807 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100808 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000809 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100810 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000811 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100812 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
813 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100814 }
815 }
816}
817
818void CodeGeneratorARM::Move64(Location destination, Location source) {
819 if (source.Equals(destination)) {
820 return;
821 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100822 if (destination.IsRegisterPair()) {
823 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000824 EmitParallelMoves(
825 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
826 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100827 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000828 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100829 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
830 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100831 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000832 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 } else {
834 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000835 DCHECK(ExpectedPairLayout(destination));
836 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
837 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100838 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000839 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100840 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000841 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
842 SP,
843 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100844 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000845 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100846 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100847 } else {
848 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100849 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000850 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100851 if (source.AsRegisterPairLow<Register>() == R1) {
852 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100853 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
854 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100855 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100856 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100857 SP, destination.GetStackIndex());
858 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000859 } else if (source.IsFpuRegisterPair()) {
860 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
861 SP,
862 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863 } else {
864 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000865 EmitParallelMoves(
866 Location::StackSlot(source.GetStackIndex()),
867 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100868 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000869 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100870 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
871 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100872 }
873 }
874}
875
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100876void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100877 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100878 if (instruction->IsCurrentMethod()) {
879 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
880 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100881 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100882 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000883 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000884 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
885 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000886 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000887 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000888 } else {
889 DCHECK(location.IsStackSlot());
890 __ LoadImmediate(IP, value);
891 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
892 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000893 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000894 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000895 int64_t value = const_to_move->AsLongConstant()->GetValue();
896 if (location.IsRegisterPair()) {
897 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
898 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
899 } else {
900 DCHECK(location.IsDoubleStackSlot());
901 __ LoadImmediate(IP, Low32Bits(value));
902 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
903 __ LoadImmediate(IP, High32Bits(value));
904 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
905 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100906 }
Roland Levillain476df552014-10-09 17:51:36 +0100907 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100908 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
909 switch (instruction->GetType()) {
910 case Primitive::kPrimBoolean:
911 case Primitive::kPrimByte:
912 case Primitive::kPrimChar:
913 case Primitive::kPrimShort:
914 case Primitive::kPrimInt:
915 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100916 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100917 Move32(location, Location::StackSlot(stack_slot));
918 break;
919
920 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100921 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100922 Move64(location, Location::DoubleStackSlot(stack_slot));
923 break;
924
925 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100926 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100927 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000928 } else if (instruction->IsTemporary()) {
929 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000930 if (temp_location.IsStackSlot()) {
931 Move32(location, temp_location);
932 } else {
933 DCHECK(temp_location.IsDoubleStackSlot());
934 Move64(location, temp_location);
935 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000936 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100937 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100938 switch (instruction->GetType()) {
939 case Primitive::kPrimBoolean:
940 case Primitive::kPrimByte:
941 case Primitive::kPrimChar:
942 case Primitive::kPrimShort:
943 case Primitive::kPrimNot:
944 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100945 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100946 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100947 break;
948
949 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100950 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100951 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100952 break;
953
954 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100955 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100956 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000957 }
958}
959
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100960void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
961 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000962 uint32_t dex_pc,
963 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100964 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100965 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
966 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000967 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100968}
969
David Brazdilfc6a86a2015-06-26 10:33:45 +0000970void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100971 DCHECK(!successor->IsExitBlock());
972
973 HBasicBlock* block = got->GetBlock();
974 HInstruction* previous = got->GetPrevious();
975
976 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000977 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100978 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
979 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
980 return;
981 }
982
983 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
984 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
985 }
986 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000987 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000988 }
989}
990
David Brazdilfc6a86a2015-06-26 10:33:45 +0000991void LocationsBuilderARM::VisitGoto(HGoto* got) {
992 got->SetLocations(nullptr);
993}
994
995void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
996 HandleGoto(got, got->GetSuccessor());
997}
998
999void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1000 try_boundary->SetLocations(nullptr);
1001}
1002
1003void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1004 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1005 if (!successor->IsExitBlock()) {
1006 HandleGoto(try_boundary, successor);
1007 }
1008}
1009
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001010void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001011 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001012}
1013
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001014void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001015 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001016}
1017
Roland Levillain4fa13f62015-07-06 18:11:54 +01001018void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1019 ShifterOperand operand;
1020 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1021 __ cmp(left, operand);
1022 } else {
1023 Register temp = IP;
1024 __ LoadImmediate(temp, right);
1025 __ cmp(left, ShifterOperand(temp));
1026 }
1027}
1028
1029void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1030 Label* true_label,
1031 Label* false_label) {
1032 __ vmstat(); // transfer FP status register to ARM APSR.
1033 if (cond->IsFPConditionTrueIfNaN()) {
1034 __ b(true_label, VS); // VS for unordered.
1035 } else if (cond->IsFPConditionFalseIfNaN()) {
1036 __ b(false_label, VS); // VS for unordered.
1037 }
1038 __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
1039}
1040
1041void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1042 Label* true_label,
1043 Label* false_label) {
1044 LocationSummary* locations = cond->GetLocations();
1045 Location left = locations->InAt(0);
1046 Location right = locations->InAt(1);
1047 IfCondition if_cond = cond->GetCondition();
1048
1049 Register left_high = left.AsRegisterPairHigh<Register>();
1050 Register left_low = left.AsRegisterPairLow<Register>();
1051 IfCondition true_high_cond = if_cond;
1052 IfCondition false_high_cond = cond->GetOppositeCondition();
1053 Condition final_condition = ARMUnsignedCondition(if_cond);
1054
1055 // Set the conditions for the test, remembering that == needs to be
1056 // decided using the low words.
1057 switch (if_cond) {
1058 case kCondEQ:
1059 case kCondNE:
1060 // Nothing to do.
1061 break;
1062 case kCondLT:
1063 false_high_cond = kCondGT;
1064 break;
1065 case kCondLE:
1066 true_high_cond = kCondLT;
1067 break;
1068 case kCondGT:
1069 false_high_cond = kCondLT;
1070 break;
1071 case kCondGE:
1072 true_high_cond = kCondGT;
1073 break;
1074 }
1075 if (right.IsConstant()) {
1076 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1077 int32_t val_low = Low32Bits(value);
1078 int32_t val_high = High32Bits(value);
1079
1080 GenerateCompareWithImmediate(left_high, val_high);
1081 if (if_cond == kCondNE) {
1082 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1083 } else if (if_cond == kCondEQ) {
1084 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1085 } else {
1086 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1087 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1088 }
1089 // Must be equal high, so compare the lows.
1090 GenerateCompareWithImmediate(left_low, val_low);
1091 } else {
1092 Register right_high = right.AsRegisterPairHigh<Register>();
1093 Register right_low = right.AsRegisterPairLow<Register>();
1094
1095 __ cmp(left_high, ShifterOperand(right_high));
1096 if (if_cond == kCondNE) {
1097 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1098 } else if (if_cond == kCondEQ) {
1099 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1100 } else {
1101 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1102 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1103 }
1104 // Must be equal high, so compare the lows.
1105 __ cmp(left_low, ShifterOperand(right_low));
1106 }
1107 // The last comparison might be unsigned.
1108 __ b(true_label, final_condition);
1109}
1110
1111void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
1112 HCondition* condition,
1113 Label* true_target,
1114 Label* false_target,
1115 Label* always_true_target) {
1116 LocationSummary* locations = condition->GetLocations();
1117 Location left = locations->InAt(0);
1118 Location right = locations->InAt(1);
1119
1120 // We don't want true_target as a nullptr.
1121 if (true_target == nullptr) {
1122 true_target = always_true_target;
1123 }
1124 bool falls_through = (false_target == nullptr);
1125
1126 // FP compares don't like null false_targets.
1127 if (false_target == nullptr) {
1128 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1129 }
1130
1131 Primitive::Type type = condition->InputAt(0)->GetType();
1132 switch (type) {
1133 case Primitive::kPrimLong:
1134 GenerateLongComparesAndJumps(condition, true_target, false_target);
1135 break;
1136 case Primitive::kPrimFloat:
1137 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1138 GenerateFPJumps(condition, true_target, false_target);
1139 break;
1140 case Primitive::kPrimDouble:
1141 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1142 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1143 GenerateFPJumps(condition, true_target, false_target);
1144 break;
1145 default:
1146 LOG(FATAL) << "Unexpected compare type " << type;
1147 }
1148
1149 if (!falls_through) {
1150 __ b(false_target);
1151 }
1152}
1153
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001154void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1155 Label* true_target,
1156 Label* false_target,
1157 Label* always_true_target) {
1158 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001159 if (cond->IsIntConstant()) {
1160 // Constant condition, statically compared against 1.
1161 int32_t cond_value = cond->AsIntConstant()->GetValue();
1162 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001163 if (always_true_target != nullptr) {
1164 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001165 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001166 return;
1167 } else {
1168 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001169 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001170 } else {
1171 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1172 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001173 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01001174 __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
1175 true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001176 } else {
1177 // Condition has not been materialized, use its inputs as the
1178 // comparison and its condition as the branch condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001179 Primitive::Type type =
1180 cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
1181 // Is this a long or FP comparison that has been folded into the HCondition?
1182 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1183 // Generate the comparison directly.
1184 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1185 true_target, false_target, always_true_target);
1186 return;
1187 }
1188
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001189 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001190 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001191 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001192 Location right = locations->InAt(1);
1193 if (right.IsRegister()) {
1194 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001195 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001196 DCHECK(right.IsConstant());
1197 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001198 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001199 __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001200 }
Dave Allison20dfc792014-06-16 20:44:29 -07001201 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001202 if (false_target != nullptr) {
1203 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001204 }
1205}
1206
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001207void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1208 LocationSummary* locations =
1209 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1210 HInstruction* cond = if_instr->InputAt(0);
1211 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1212 locations->SetInAt(0, Location::RequiresRegister());
1213 }
1214}
1215
1216void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1217 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1218 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1219 Label* always_true_target = true_target;
1220 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1221 if_instr->IfTrueSuccessor())) {
1222 always_true_target = nullptr;
1223 }
1224 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1225 if_instr->IfFalseSuccessor())) {
1226 false_target = nullptr;
1227 }
1228 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1229}
1230
1231void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1232 LocationSummary* locations = new (GetGraph()->GetArena())
1233 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1234 HInstruction* cond = deoptimize->InputAt(0);
1235 DCHECK(cond->IsCondition());
1236 if (cond->AsCondition()->NeedsMaterialization()) {
1237 locations->SetInAt(0, Location::RequiresRegister());
1238 }
1239}
1240
1241void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1242 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
1243 DeoptimizationSlowPathARM(deoptimize);
1244 codegen_->AddSlowPath(slow_path);
1245 Label* slow_path_entry = slow_path->GetEntryLabel();
1246 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1247}
Dave Allison20dfc792014-06-16 20:44:29 -07001248
Roland Levillain0d37cd02015-05-27 16:39:19 +01001249void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001250 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001251 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001252 // Handle the long/FP comparisons made in instruction simplification.
1253 switch (cond->InputAt(0)->GetType()) {
1254 case Primitive::kPrimLong:
1255 locations->SetInAt(0, Location::RequiresRegister());
1256 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1257 if (cond->NeedsMaterialization()) {
1258 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1259 }
1260 break;
1261
1262 case Primitive::kPrimFloat:
1263 case Primitive::kPrimDouble:
1264 locations->SetInAt(0, Location::RequiresFpuRegister());
1265 locations->SetInAt(1, Location::RequiresFpuRegister());
1266 if (cond->NeedsMaterialization()) {
1267 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1268 }
1269 break;
1270
1271 default:
1272 locations->SetInAt(0, Location::RequiresRegister());
1273 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1274 if (cond->NeedsMaterialization()) {
1275 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1276 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001277 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001278}
1279
Roland Levillain0d37cd02015-05-27 16:39:19 +01001280void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001281 if (!cond->NeedsMaterialization()) {
1282 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001283 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001284
1285 LocationSummary* locations = cond->GetLocations();
1286 Location left = locations->InAt(0);
1287 Location right = locations->InAt(1);
1288 Register out = locations->Out().AsRegister<Register>();
1289 Label true_label, false_label;
1290
1291 switch (cond->InputAt(0)->GetType()) {
1292 default: {
1293 // Integer case.
1294 if (right.IsRegister()) {
1295 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1296 } else {
1297 DCHECK(right.IsConstant());
1298 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1299 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1300 }
1301 __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
1302 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1303 ARMSignedOrFPCondition(cond->GetCondition()));
1304 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1305 ARMSignedOrFPCondition(cond->GetOppositeCondition()));
1306 return;
1307 }
1308 case Primitive::kPrimLong:
1309 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1310 break;
1311 case Primitive::kPrimFloat:
1312 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1313 GenerateFPJumps(cond, &true_label, &false_label);
1314 break;
1315 case Primitive::kPrimDouble:
1316 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1317 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1318 GenerateFPJumps(cond, &true_label, &false_label);
1319 break;
1320 }
1321
1322 // Convert the jumps into the result.
1323 Label done_label;
1324
1325 // False case: result = 0.
1326 __ Bind(&false_label);
1327 __ LoadImmediate(out, 0);
1328 __ b(&done_label);
1329
1330 // True case: result = 1.
1331 __ Bind(&true_label);
1332 __ LoadImmediate(out, 1);
1333 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001334}
1335
1336void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1337 VisitCondition(comp);
1338}
1339
1340void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1341 VisitCondition(comp);
1342}
1343
1344void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1345 VisitCondition(comp);
1346}
1347
1348void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1349 VisitCondition(comp);
1350}
1351
1352void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1353 VisitCondition(comp);
1354}
1355
1356void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1357 VisitCondition(comp);
1358}
1359
1360void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1361 VisitCondition(comp);
1362}
1363
1364void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1365 VisitCondition(comp);
1366}
1367
1368void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1369 VisitCondition(comp);
1370}
1371
1372void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1373 VisitCondition(comp);
1374}
1375
1376void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1377 VisitCondition(comp);
1378}
1379
1380void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1381 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001382}
1383
1384void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001385 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001386}
1387
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001388void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1389 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001390}
1391
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001392void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001393 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001394}
1395
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001396void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001397 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001398 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001399}
1400
1401void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001402 LocationSummary* locations =
1403 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001404 switch (store->InputAt(1)->GetType()) {
1405 case Primitive::kPrimBoolean:
1406 case Primitive::kPrimByte:
1407 case Primitive::kPrimChar:
1408 case Primitive::kPrimShort:
1409 case Primitive::kPrimInt:
1410 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001411 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001412 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1413 break;
1414
1415 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001416 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001417 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1418 break;
1419
1420 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001421 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001422 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001423}
1424
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001425void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001426 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001427}
1428
1429void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001430 LocationSummary* locations =
1431 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001432 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001433}
1434
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001435void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001436 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001437 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001438}
1439
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001440void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1441 LocationSummary* locations =
1442 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1443 locations->SetOut(Location::ConstantLocation(constant));
1444}
1445
1446void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1447 // Will be generated at use site.
1448 UNUSED(constant);
1449}
1450
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001451void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001452 LocationSummary* locations =
1453 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001454 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001455}
1456
1457void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1458 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001459 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001460}
1461
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001462void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1463 LocationSummary* locations =
1464 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1465 locations->SetOut(Location::ConstantLocation(constant));
1466}
1467
1468void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1469 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001470 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001471}
1472
1473void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1474 LocationSummary* locations =
1475 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1476 locations->SetOut(Location::ConstantLocation(constant));
1477}
1478
1479void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1480 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001481 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001482}
1483
Calin Juravle27df7582015-04-17 19:12:31 +01001484void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1485 memory_barrier->SetLocations(nullptr);
1486}
1487
1488void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1489 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1490}
1491
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001492void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001493 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001494}
1495
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001496void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001497 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001498 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001499}
1500
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001501void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001502 LocationSummary* locations =
1503 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001504 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001505}
1506
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001507void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001508 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001509 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001510}
1511
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001512void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001513 // When we do not run baseline, explicit clinit checks triggered by static
1514 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1515 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001516
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001517 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1518 codegen_->GetInstructionSetFeatures());
1519 if (intrinsic.TryDispatch(invoke)) {
1520 return;
1521 }
1522
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001523 HandleInvoke(invoke);
1524}
1525
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001526static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1527 if (invoke->GetLocations()->Intrinsified()) {
1528 IntrinsicCodeGeneratorARM intrinsic(codegen);
1529 intrinsic.Dispatch(invoke);
1530 return true;
1531 }
1532 return false;
1533}
1534
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001535void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001536 // When we do not run baseline, explicit clinit checks triggered by static
1537 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1538 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001539
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001540 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1541 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001542 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001543
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001544 LocationSummary* locations = invoke->GetLocations();
1545 codegen_->GenerateStaticOrDirectCall(
1546 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001547 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001548}
1549
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001550void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001551 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001552 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001553}
1554
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001555void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001556 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1557 codegen_->GetInstructionSetFeatures());
1558 if (intrinsic.TryDispatch(invoke)) {
1559 return;
1560 }
1561
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001562 HandleInvoke(invoke);
1563}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001564
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001565void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001566 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1567 return;
1568 }
1569
Roland Levillain271ab9c2014-11-27 15:23:57 +00001570 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001571 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1572 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001573 LocationSummary* locations = invoke->GetLocations();
1574 Location receiver = locations->InAt(0);
1575 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1576 // temp = object->GetClass();
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001577 DCHECK(receiver.IsRegister());
1578 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00001579 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001580 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001581 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001582 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001583 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001584 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001585 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001586 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001587 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001588 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001589 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001590 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001591}
1592
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001593void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1594 HandleInvoke(invoke);
1595 // Add the hidden argument.
1596 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1597}
1598
1599void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1600 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001601 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001602 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1603 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001604 LocationSummary* locations = invoke->GetLocations();
1605 Location receiver = locations->InAt(0);
1606 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1607
1608 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001609 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1610 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001611
1612 // temp = object->GetClass();
1613 if (receiver.IsStackSlot()) {
1614 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1615 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1616 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001617 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001618 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001619 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001620 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001621 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001622 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001623 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001624 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1625 // LR = temp->GetEntryPoint();
1626 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1627 // LR();
1628 __ blx(LR);
1629 DCHECK(!codegen_->IsLeafMethod());
1630 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1631}
1632
Roland Levillain88cb1752014-10-20 16:36:47 +01001633void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1634 LocationSummary* locations =
1635 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1636 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001637 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001638 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001639 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1640 break;
1641 }
1642 case Primitive::kPrimLong: {
1643 locations->SetInAt(0, Location::RequiresRegister());
1644 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001645 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001646 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001647
Roland Levillain88cb1752014-10-20 16:36:47 +01001648 case Primitive::kPrimFloat:
1649 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001650 locations->SetInAt(0, Location::RequiresFpuRegister());
1651 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001652 break;
1653
1654 default:
1655 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1656 }
1657}
1658
1659void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1660 LocationSummary* locations = neg->GetLocations();
1661 Location out = locations->Out();
1662 Location in = locations->InAt(0);
1663 switch (neg->GetResultType()) {
1664 case Primitive::kPrimInt:
1665 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001666 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001667 break;
1668
1669 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001670 DCHECK(in.IsRegisterPair());
1671 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1672 __ rsbs(out.AsRegisterPairLow<Register>(),
1673 in.AsRegisterPairLow<Register>(),
1674 ShifterOperand(0));
1675 // We cannot emit an RSC (Reverse Subtract with Carry)
1676 // instruction here, as it does not exist in the Thumb-2
1677 // instruction set. We use the following approach
1678 // using SBC and SUB instead.
1679 //
1680 // out.hi = -C
1681 __ sbc(out.AsRegisterPairHigh<Register>(),
1682 out.AsRegisterPairHigh<Register>(),
1683 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1684 // out.hi = out.hi - in.hi
1685 __ sub(out.AsRegisterPairHigh<Register>(),
1686 out.AsRegisterPairHigh<Register>(),
1687 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1688 break;
1689
Roland Levillain88cb1752014-10-20 16:36:47 +01001690 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001691 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001692 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001693 break;
1694
Roland Levillain88cb1752014-10-20 16:36:47 +01001695 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001696 DCHECK(in.IsFpuRegisterPair());
1697 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1698 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001699 break;
1700
1701 default:
1702 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1703 }
1704}
1705
Roland Levillaindff1f282014-11-05 14:15:05 +00001706void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001707 Primitive::Type result_type = conversion->GetResultType();
1708 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001709 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001710
Roland Levillain5b3ee562015-04-14 16:02:41 +01001711 // The float-to-long, double-to-long and long-to-float type conversions
1712 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001713 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001714 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1715 && result_type == Primitive::kPrimLong)
1716 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001717 ? LocationSummary::kCall
1718 : LocationSummary::kNoCall;
1719 LocationSummary* locations =
1720 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1721
David Brazdilb2bd1c52015-03-25 11:17:37 +00001722 // The Java language does not allow treating boolean as an integral type but
1723 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001724
Roland Levillaindff1f282014-11-05 14:15:05 +00001725 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001726 case Primitive::kPrimByte:
1727 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001728 case Primitive::kPrimBoolean:
1729 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001730 case Primitive::kPrimShort:
1731 case Primitive::kPrimInt:
1732 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001733 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001734 locations->SetInAt(0, Location::RequiresRegister());
1735 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1736 break;
1737
1738 default:
1739 LOG(FATAL) << "Unexpected type conversion from " << input_type
1740 << " to " << result_type;
1741 }
1742 break;
1743
Roland Levillain01a8d712014-11-14 16:27:39 +00001744 case Primitive::kPrimShort:
1745 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001746 case Primitive::kPrimBoolean:
1747 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001748 case Primitive::kPrimByte:
1749 case Primitive::kPrimInt:
1750 case Primitive::kPrimChar:
1751 // Processing a Dex `int-to-short' instruction.
1752 locations->SetInAt(0, Location::RequiresRegister());
1753 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1754 break;
1755
1756 default:
1757 LOG(FATAL) << "Unexpected type conversion from " << input_type
1758 << " to " << result_type;
1759 }
1760 break;
1761
Roland Levillain946e1432014-11-11 17:35:19 +00001762 case Primitive::kPrimInt:
1763 switch (input_type) {
1764 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001765 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001766 locations->SetInAt(0, Location::Any());
1767 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1768 break;
1769
1770 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001771 // Processing a Dex `float-to-int' instruction.
1772 locations->SetInAt(0, Location::RequiresFpuRegister());
1773 locations->SetOut(Location::RequiresRegister());
1774 locations->AddTemp(Location::RequiresFpuRegister());
1775 break;
1776
Roland Levillain946e1432014-11-11 17:35:19 +00001777 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001778 // Processing a Dex `double-to-int' instruction.
1779 locations->SetInAt(0, Location::RequiresFpuRegister());
1780 locations->SetOut(Location::RequiresRegister());
1781 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001782 break;
1783
1784 default:
1785 LOG(FATAL) << "Unexpected type conversion from " << input_type
1786 << " to " << result_type;
1787 }
1788 break;
1789
Roland Levillaindff1f282014-11-05 14:15:05 +00001790 case Primitive::kPrimLong:
1791 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001792 case Primitive::kPrimBoolean:
1793 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001794 case Primitive::kPrimByte:
1795 case Primitive::kPrimShort:
1796 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001797 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001798 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001799 locations->SetInAt(0, Location::RequiresRegister());
1800 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1801 break;
1802
Roland Levillain624279f2014-12-04 11:54:28 +00001803 case Primitive::kPrimFloat: {
1804 // Processing a Dex `float-to-long' instruction.
1805 InvokeRuntimeCallingConvention calling_convention;
1806 locations->SetInAt(0, Location::FpuRegisterLocation(
1807 calling_convention.GetFpuRegisterAt(0)));
1808 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1809 break;
1810 }
1811
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001812 case Primitive::kPrimDouble: {
1813 // Processing a Dex `double-to-long' instruction.
1814 InvokeRuntimeCallingConvention calling_convention;
1815 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1816 calling_convention.GetFpuRegisterAt(0),
1817 calling_convention.GetFpuRegisterAt(1)));
1818 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001819 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001820 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001821
1822 default:
1823 LOG(FATAL) << "Unexpected type conversion from " << input_type
1824 << " to " << result_type;
1825 }
1826 break;
1827
Roland Levillain981e4542014-11-14 11:47:14 +00001828 case Primitive::kPrimChar:
1829 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001830 case Primitive::kPrimBoolean:
1831 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001832 case Primitive::kPrimByte:
1833 case Primitive::kPrimShort:
1834 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001835 // Processing a Dex `int-to-char' instruction.
1836 locations->SetInAt(0, Location::RequiresRegister());
1837 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1838 break;
1839
1840 default:
1841 LOG(FATAL) << "Unexpected type conversion from " << input_type
1842 << " to " << result_type;
1843 }
1844 break;
1845
Roland Levillaindff1f282014-11-05 14:15:05 +00001846 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001847 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001848 case Primitive::kPrimBoolean:
1849 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001850 case Primitive::kPrimByte:
1851 case Primitive::kPrimShort:
1852 case Primitive::kPrimInt:
1853 case Primitive::kPrimChar:
1854 // Processing a Dex `int-to-float' instruction.
1855 locations->SetInAt(0, Location::RequiresRegister());
1856 locations->SetOut(Location::RequiresFpuRegister());
1857 break;
1858
Roland Levillain5b3ee562015-04-14 16:02:41 +01001859 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001860 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001861 InvokeRuntimeCallingConvention calling_convention;
1862 locations->SetInAt(0, Location::RegisterPairLocation(
1863 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1864 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001865 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001866 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001867
Roland Levillaincff13742014-11-17 14:32:17 +00001868 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001869 // Processing a Dex `double-to-float' instruction.
1870 locations->SetInAt(0, Location::RequiresFpuRegister());
1871 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001872 break;
1873
1874 default:
1875 LOG(FATAL) << "Unexpected type conversion from " << input_type
1876 << " to " << result_type;
1877 };
1878 break;
1879
Roland Levillaindff1f282014-11-05 14:15:05 +00001880 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001881 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001882 case Primitive::kPrimBoolean:
1883 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001884 case Primitive::kPrimByte:
1885 case Primitive::kPrimShort:
1886 case Primitive::kPrimInt:
1887 case Primitive::kPrimChar:
1888 // Processing a Dex `int-to-double' instruction.
1889 locations->SetInAt(0, Location::RequiresRegister());
1890 locations->SetOut(Location::RequiresFpuRegister());
1891 break;
1892
1893 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001894 // Processing a Dex `long-to-double' instruction.
1895 locations->SetInAt(0, Location::RequiresRegister());
1896 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01001897 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001898 locations->AddTemp(Location::RequiresFpuRegister());
1899 break;
1900
Roland Levillaincff13742014-11-17 14:32:17 +00001901 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001902 // Processing a Dex `float-to-double' instruction.
1903 locations->SetInAt(0, Location::RequiresFpuRegister());
1904 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001905 break;
1906
1907 default:
1908 LOG(FATAL) << "Unexpected type conversion from " << input_type
1909 << " to " << result_type;
1910 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001911 break;
1912
1913 default:
1914 LOG(FATAL) << "Unexpected type conversion from " << input_type
1915 << " to " << result_type;
1916 }
1917}
1918
1919void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1920 LocationSummary* locations = conversion->GetLocations();
1921 Location out = locations->Out();
1922 Location in = locations->InAt(0);
1923 Primitive::Type result_type = conversion->GetResultType();
1924 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001925 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001926 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001927 case Primitive::kPrimByte:
1928 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001929 case Primitive::kPrimBoolean:
1930 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001931 case Primitive::kPrimShort:
1932 case Primitive::kPrimInt:
1933 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001934 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001935 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001936 break;
1937
1938 default:
1939 LOG(FATAL) << "Unexpected type conversion from " << input_type
1940 << " to " << result_type;
1941 }
1942 break;
1943
Roland Levillain01a8d712014-11-14 16:27:39 +00001944 case Primitive::kPrimShort:
1945 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001946 case Primitive::kPrimBoolean:
1947 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001948 case Primitive::kPrimByte:
1949 case Primitive::kPrimInt:
1950 case Primitive::kPrimChar:
1951 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001952 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001953 break;
1954
1955 default:
1956 LOG(FATAL) << "Unexpected type conversion from " << input_type
1957 << " to " << result_type;
1958 }
1959 break;
1960
Roland Levillain946e1432014-11-11 17:35:19 +00001961 case Primitive::kPrimInt:
1962 switch (input_type) {
1963 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001964 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001965 DCHECK(out.IsRegister());
1966 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001967 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001968 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001969 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001970 } else {
1971 DCHECK(in.IsConstant());
1972 DCHECK(in.GetConstant()->IsLongConstant());
1973 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001974 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001975 }
1976 break;
1977
Roland Levillain3f8f9362014-12-02 17:45:01 +00001978 case Primitive::kPrimFloat: {
1979 // Processing a Dex `float-to-int' instruction.
1980 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1981 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1982 __ vcvtis(temp, temp);
1983 __ vmovrs(out.AsRegister<Register>(), temp);
1984 break;
1985 }
1986
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001987 case Primitive::kPrimDouble: {
1988 // Processing a Dex `double-to-int' instruction.
1989 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1990 DRegister temp_d = FromLowSToD(temp_s);
1991 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1992 __ vcvtid(temp_s, temp_d);
1993 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001994 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001995 }
Roland Levillain946e1432014-11-11 17:35:19 +00001996
1997 default:
1998 LOG(FATAL) << "Unexpected type conversion from " << input_type
1999 << " to " << result_type;
2000 }
2001 break;
2002
Roland Levillaindff1f282014-11-05 14:15:05 +00002003 case Primitive::kPrimLong:
2004 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002005 case Primitive::kPrimBoolean:
2006 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002007 case Primitive::kPrimByte:
2008 case Primitive::kPrimShort:
2009 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002010 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002011 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002012 DCHECK(out.IsRegisterPair());
2013 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002014 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002015 // Sign extension.
2016 __ Asr(out.AsRegisterPairHigh<Register>(),
2017 out.AsRegisterPairLow<Register>(),
2018 31);
2019 break;
2020
2021 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002022 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002023 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2024 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002025 conversion->GetDexPc(),
2026 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002027 break;
2028
Roland Levillaindff1f282014-11-05 14:15:05 +00002029 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002030 // Processing a Dex `double-to-long' instruction.
2031 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2032 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002033 conversion->GetDexPc(),
2034 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002035 break;
2036
2037 default:
2038 LOG(FATAL) << "Unexpected type conversion from " << input_type
2039 << " to " << result_type;
2040 }
2041 break;
2042
Roland Levillain981e4542014-11-14 11:47:14 +00002043 case Primitive::kPrimChar:
2044 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002045 case Primitive::kPrimBoolean:
2046 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002047 case Primitive::kPrimByte:
2048 case Primitive::kPrimShort:
2049 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002050 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002051 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002052 break;
2053
2054 default:
2055 LOG(FATAL) << "Unexpected type conversion from " << input_type
2056 << " to " << result_type;
2057 }
2058 break;
2059
Roland Levillaindff1f282014-11-05 14:15:05 +00002060 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002061 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002062 case Primitive::kPrimBoolean:
2063 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002064 case Primitive::kPrimByte:
2065 case Primitive::kPrimShort:
2066 case Primitive::kPrimInt:
2067 case Primitive::kPrimChar: {
2068 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002069 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2070 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002071 break;
2072 }
2073
Roland Levillain5b3ee562015-04-14 16:02:41 +01002074 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002075 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002076 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2077 conversion,
2078 conversion->GetDexPc(),
2079 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002080 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002081
Roland Levillaincff13742014-11-17 14:32:17 +00002082 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002083 // Processing a Dex `double-to-float' instruction.
2084 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2085 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002086 break;
2087
2088 default:
2089 LOG(FATAL) << "Unexpected type conversion from " << input_type
2090 << " to " << result_type;
2091 };
2092 break;
2093
Roland Levillaindff1f282014-11-05 14:15:05 +00002094 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002095 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002096 case Primitive::kPrimBoolean:
2097 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002098 case Primitive::kPrimByte:
2099 case Primitive::kPrimShort:
2100 case Primitive::kPrimInt:
2101 case Primitive::kPrimChar: {
2102 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002103 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002104 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2105 out.AsFpuRegisterPairLow<SRegister>());
2106 break;
2107 }
2108
Roland Levillain647b9ed2014-11-27 12:06:00 +00002109 case Primitive::kPrimLong: {
2110 // Processing a Dex `long-to-double' instruction.
2111 Register low = in.AsRegisterPairLow<Register>();
2112 Register high = in.AsRegisterPairHigh<Register>();
2113 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2114 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002115 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002116 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002117 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2118 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002119
Roland Levillain682393c2015-04-14 15:57:52 +01002120 // temp_d = int-to-double(high)
2121 __ vmovsr(temp_s, high);
2122 __ vcvtdi(temp_d, temp_s);
2123 // constant_d = k2Pow32EncodingForDouble
2124 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2125 // out_d = unsigned-to-double(low)
2126 __ vmovsr(out_s, low);
2127 __ vcvtdu(out_d, out_s);
2128 // out_d += temp_d * constant_d
2129 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002130 break;
2131 }
2132
Roland Levillaincff13742014-11-17 14:32:17 +00002133 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002134 // Processing a Dex `float-to-double' instruction.
2135 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2136 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002137 break;
2138
2139 default:
2140 LOG(FATAL) << "Unexpected type conversion from " << input_type
2141 << " to " << result_type;
2142 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002143 break;
2144
2145 default:
2146 LOG(FATAL) << "Unexpected type conversion from " << input_type
2147 << " to " << result_type;
2148 }
2149}
2150
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002151void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002152 LocationSummary* locations =
2153 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002154 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002155 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002156 locations->SetInAt(0, Location::RequiresRegister());
2157 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002158 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2159 break;
2160 }
2161
2162 case Primitive::kPrimLong: {
2163 locations->SetInAt(0, Location::RequiresRegister());
2164 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002165 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002166 break;
2167 }
2168
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002169 case Primitive::kPrimFloat:
2170 case Primitive::kPrimDouble: {
2171 locations->SetInAt(0, Location::RequiresFpuRegister());
2172 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002173 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002174 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002175 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002176
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002177 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002178 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002179 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002180}
2181
2182void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2183 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002184 Location out = locations->Out();
2185 Location first = locations->InAt(0);
2186 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002187 switch (add->GetResultType()) {
2188 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002189 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002190 __ add(out.AsRegister<Register>(),
2191 first.AsRegister<Register>(),
2192 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002193 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002194 __ AddConstant(out.AsRegister<Register>(),
2195 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002196 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002197 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002198 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002199
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002200 case Primitive::kPrimLong: {
2201 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002202 __ adds(out.AsRegisterPairLow<Register>(),
2203 first.AsRegisterPairLow<Register>(),
2204 ShifterOperand(second.AsRegisterPairLow<Register>()));
2205 __ adc(out.AsRegisterPairHigh<Register>(),
2206 first.AsRegisterPairHigh<Register>(),
2207 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002208 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002209 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002210
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002211 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002212 __ vadds(out.AsFpuRegister<SRegister>(),
2213 first.AsFpuRegister<SRegister>(),
2214 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002215 break;
2216
2217 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002218 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2219 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2220 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002221 break;
2222
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002223 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002224 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002225 }
2226}
2227
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002228void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002229 LocationSummary* locations =
2230 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002231 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002232 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002233 locations->SetInAt(0, Location::RequiresRegister());
2234 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002235 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2236 break;
2237 }
2238
2239 case Primitive::kPrimLong: {
2240 locations->SetInAt(0, Location::RequiresRegister());
2241 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002242 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002243 break;
2244 }
Calin Juravle11351682014-10-23 15:38:15 +01002245 case Primitive::kPrimFloat:
2246 case Primitive::kPrimDouble: {
2247 locations->SetInAt(0, Location::RequiresFpuRegister());
2248 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002249 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002250 break;
Calin Juravle11351682014-10-23 15:38:15 +01002251 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002252 default:
Calin Juravle11351682014-10-23 15:38:15 +01002253 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002254 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002255}
2256
2257void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2258 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002259 Location out = locations->Out();
2260 Location first = locations->InAt(0);
2261 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002262 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002263 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002264 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002265 __ sub(out.AsRegister<Register>(),
2266 first.AsRegister<Register>(),
2267 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002268 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002269 __ AddConstant(out.AsRegister<Register>(),
2270 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002271 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002272 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002273 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002274 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002275
Calin Juravle11351682014-10-23 15:38:15 +01002276 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002277 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002278 __ subs(out.AsRegisterPairLow<Register>(),
2279 first.AsRegisterPairLow<Register>(),
2280 ShifterOperand(second.AsRegisterPairLow<Register>()));
2281 __ sbc(out.AsRegisterPairHigh<Register>(),
2282 first.AsRegisterPairHigh<Register>(),
2283 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002284 break;
Calin Juravle11351682014-10-23 15:38:15 +01002285 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002286
Calin Juravle11351682014-10-23 15:38:15 +01002287 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002288 __ vsubs(out.AsFpuRegister<SRegister>(),
2289 first.AsFpuRegister<SRegister>(),
2290 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002291 break;
Calin Juravle11351682014-10-23 15:38:15 +01002292 }
2293
2294 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002295 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2296 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2297 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002298 break;
2299 }
2300
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002301
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002302 default:
Calin Juravle11351682014-10-23 15:38:15 +01002303 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002304 }
2305}
2306
Calin Juravle34bacdf2014-10-07 20:23:36 +01002307void LocationsBuilderARM::VisitMul(HMul* mul) {
2308 LocationSummary* locations =
2309 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2310 switch (mul->GetResultType()) {
2311 case Primitive::kPrimInt:
2312 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002313 locations->SetInAt(0, Location::RequiresRegister());
2314 locations->SetInAt(1, Location::RequiresRegister());
2315 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002316 break;
2317 }
2318
Calin Juravleb5bfa962014-10-21 18:02:24 +01002319 case Primitive::kPrimFloat:
2320 case Primitive::kPrimDouble: {
2321 locations->SetInAt(0, Location::RequiresFpuRegister());
2322 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002323 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002324 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002325 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002326
2327 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002328 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002329 }
2330}
2331
2332void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2333 LocationSummary* locations = mul->GetLocations();
2334 Location out = locations->Out();
2335 Location first = locations->InAt(0);
2336 Location second = locations->InAt(1);
2337 switch (mul->GetResultType()) {
2338 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002339 __ mul(out.AsRegister<Register>(),
2340 first.AsRegister<Register>(),
2341 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002342 break;
2343 }
2344 case Primitive::kPrimLong: {
2345 Register out_hi = out.AsRegisterPairHigh<Register>();
2346 Register out_lo = out.AsRegisterPairLow<Register>();
2347 Register in1_hi = first.AsRegisterPairHigh<Register>();
2348 Register in1_lo = first.AsRegisterPairLow<Register>();
2349 Register in2_hi = second.AsRegisterPairHigh<Register>();
2350 Register in2_lo = second.AsRegisterPairLow<Register>();
2351
2352 // Extra checks to protect caused by the existence of R1_R2.
2353 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2354 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2355 DCHECK_NE(out_hi, in1_lo);
2356 DCHECK_NE(out_hi, in2_lo);
2357
2358 // input: in1 - 64 bits, in2 - 64 bits
2359 // output: out
2360 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2361 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2362 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2363
2364 // IP <- in1.lo * in2.hi
2365 __ mul(IP, in1_lo, in2_hi);
2366 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2367 __ mla(out_hi, in1_hi, in2_lo, IP);
2368 // out.lo <- (in1.lo * in2.lo)[31:0];
2369 __ umull(out_lo, IP, in1_lo, in2_lo);
2370 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2371 __ add(out_hi, out_hi, ShifterOperand(IP));
2372 break;
2373 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002374
2375 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002376 __ vmuls(out.AsFpuRegister<SRegister>(),
2377 first.AsFpuRegister<SRegister>(),
2378 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002379 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002380 }
2381
2382 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002383 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2384 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2385 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002386 break;
2387 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002388
2389 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002390 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002391 }
2392}
2393
Zheng Xuc6667102015-05-15 16:08:45 +08002394void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2395 DCHECK(instruction->IsDiv() || instruction->IsRem());
2396 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2397
2398 LocationSummary* locations = instruction->GetLocations();
2399 Location second = locations->InAt(1);
2400 DCHECK(second.IsConstant());
2401
2402 Register out = locations->Out().AsRegister<Register>();
2403 Register dividend = locations->InAt(0).AsRegister<Register>();
2404 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2405 DCHECK(imm == 1 || imm == -1);
2406
2407 if (instruction->IsRem()) {
2408 __ LoadImmediate(out, 0);
2409 } else {
2410 if (imm == 1) {
2411 __ Mov(out, dividend);
2412 } else {
2413 __ rsb(out, dividend, ShifterOperand(0));
2414 }
2415 }
2416}
2417
2418void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2419 DCHECK(instruction->IsDiv() || instruction->IsRem());
2420 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2421
2422 LocationSummary* locations = instruction->GetLocations();
2423 Location second = locations->InAt(1);
2424 DCHECK(second.IsConstant());
2425
2426 Register out = locations->Out().AsRegister<Register>();
2427 Register dividend = locations->InAt(0).AsRegister<Register>();
2428 Register temp = locations->GetTemp(0).AsRegister<Register>();
2429 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002430 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002431 DCHECK(IsPowerOfTwo(abs_imm));
2432 int ctz_imm = CTZ(abs_imm);
2433
2434 if (ctz_imm == 1) {
2435 __ Lsr(temp, dividend, 32 - ctz_imm);
2436 } else {
2437 __ Asr(temp, dividend, 31);
2438 __ Lsr(temp, temp, 32 - ctz_imm);
2439 }
2440 __ add(out, temp, ShifterOperand(dividend));
2441
2442 if (instruction->IsDiv()) {
2443 __ Asr(out, out, ctz_imm);
2444 if (imm < 0) {
2445 __ rsb(out, out, ShifterOperand(0));
2446 }
2447 } else {
2448 __ ubfx(out, out, 0, ctz_imm);
2449 __ sub(out, out, ShifterOperand(temp));
2450 }
2451}
2452
2453void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2454 DCHECK(instruction->IsDiv() || instruction->IsRem());
2455 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2456
2457 LocationSummary* locations = instruction->GetLocations();
2458 Location second = locations->InAt(1);
2459 DCHECK(second.IsConstant());
2460
2461 Register out = locations->Out().AsRegister<Register>();
2462 Register dividend = locations->InAt(0).AsRegister<Register>();
2463 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2464 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2465 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2466
2467 int64_t magic;
2468 int shift;
2469 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2470
2471 __ LoadImmediate(temp1, magic);
2472 __ smull(temp2, temp1, dividend, temp1);
2473
2474 if (imm > 0 && magic < 0) {
2475 __ add(temp1, temp1, ShifterOperand(dividend));
2476 } else if (imm < 0 && magic > 0) {
2477 __ sub(temp1, temp1, ShifterOperand(dividend));
2478 }
2479
2480 if (shift != 0) {
2481 __ Asr(temp1, temp1, shift);
2482 }
2483
2484 if (instruction->IsDiv()) {
2485 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2486 } else {
2487 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2488 // TODO: Strength reduction for mls.
2489 __ LoadImmediate(temp2, imm);
2490 __ mls(out, temp1, temp2, dividend);
2491 }
2492}
2493
2494void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2495 DCHECK(instruction->IsDiv() || instruction->IsRem());
2496 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2497
2498 LocationSummary* locations = instruction->GetLocations();
2499 Location second = locations->InAt(1);
2500 DCHECK(second.IsConstant());
2501
2502 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2503 if (imm == 0) {
2504 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2505 } else if (imm == 1 || imm == -1) {
2506 DivRemOneOrMinusOne(instruction);
2507 } else if (IsPowerOfTwo(std::abs(imm))) {
2508 DivRemByPowerOfTwo(instruction);
2509 } else {
2510 DCHECK(imm <= -2 || imm >= 2);
2511 GenerateDivRemWithAnyConstant(instruction);
2512 }
2513}
2514
Calin Juravle7c4954d2014-10-28 16:57:40 +00002515void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002516 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2517 if (div->GetResultType() == Primitive::kPrimLong) {
2518 // pLdiv runtime call.
2519 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002520 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2521 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002522 } else if (div->GetResultType() == Primitive::kPrimInt &&
2523 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2524 // pIdivmod runtime call.
2525 call_kind = LocationSummary::kCall;
2526 }
2527
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002528 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2529
Calin Juravle7c4954d2014-10-28 16:57:40 +00002530 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002531 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002532 if (div->InputAt(1)->IsConstant()) {
2533 locations->SetInAt(0, Location::RequiresRegister());
2534 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2535 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2536 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2537 if (abs_imm <= 1) {
2538 // No temp register required.
2539 } else {
2540 locations->AddTemp(Location::RequiresRegister());
2541 if (!IsPowerOfTwo(abs_imm)) {
2542 locations->AddTemp(Location::RequiresRegister());
2543 }
2544 }
2545 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002546 locations->SetInAt(0, Location::RequiresRegister());
2547 locations->SetInAt(1, Location::RequiresRegister());
2548 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2549 } else {
2550 InvokeRuntimeCallingConvention calling_convention;
2551 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2552 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2553 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2554 // we only need the former.
2555 locations->SetOut(Location::RegisterLocation(R0));
2556 }
Calin Juravled0d48522014-11-04 16:40:20 +00002557 break;
2558 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002559 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002560 InvokeRuntimeCallingConvention calling_convention;
2561 locations->SetInAt(0, Location::RegisterPairLocation(
2562 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2563 locations->SetInAt(1, Location::RegisterPairLocation(
2564 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002565 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002566 break;
2567 }
2568 case Primitive::kPrimFloat:
2569 case Primitive::kPrimDouble: {
2570 locations->SetInAt(0, Location::RequiresFpuRegister());
2571 locations->SetInAt(1, Location::RequiresFpuRegister());
2572 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2573 break;
2574 }
2575
2576 default:
2577 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2578 }
2579}
2580
2581void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2582 LocationSummary* locations = div->GetLocations();
2583 Location out = locations->Out();
2584 Location first = locations->InAt(0);
2585 Location second = locations->InAt(1);
2586
2587 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002588 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002589 if (second.IsConstant()) {
2590 GenerateDivRemConstantIntegral(div);
2591 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002592 __ sdiv(out.AsRegister<Register>(),
2593 first.AsRegister<Register>(),
2594 second.AsRegister<Register>());
2595 } else {
2596 InvokeRuntimeCallingConvention calling_convention;
2597 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2598 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2599 DCHECK_EQ(R0, out.AsRegister<Register>());
2600
2601 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2602 }
Calin Juravled0d48522014-11-04 16:40:20 +00002603 break;
2604 }
2605
Calin Juravle7c4954d2014-10-28 16:57:40 +00002606 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002607 InvokeRuntimeCallingConvention calling_convention;
2608 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2609 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2610 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2611 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2612 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002613 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002614
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002615 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002616 break;
2617 }
2618
2619 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002620 __ vdivs(out.AsFpuRegister<SRegister>(),
2621 first.AsFpuRegister<SRegister>(),
2622 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002623 break;
2624 }
2625
2626 case Primitive::kPrimDouble: {
2627 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2628 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2629 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2630 break;
2631 }
2632
2633 default:
2634 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2635 }
2636}
2637
Calin Juravlebacfec32014-11-14 15:54:36 +00002638void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002639 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002640
2641 // Most remainders are implemented in the runtime.
2642 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002643 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2644 // sdiv will be replaced by other instruction sequence.
2645 call_kind = LocationSummary::kNoCall;
2646 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2647 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002648 // Have hardware divide instruction for int, do it with three instructions.
2649 call_kind = LocationSummary::kNoCall;
2650 }
2651
Calin Juravlebacfec32014-11-14 15:54:36 +00002652 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2653
Calin Juravled2ec87d2014-12-08 14:24:46 +00002654 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002655 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002656 if (rem->InputAt(1)->IsConstant()) {
2657 locations->SetInAt(0, Location::RequiresRegister());
2658 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2659 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2660 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2661 if (abs_imm <= 1) {
2662 // No temp register required.
2663 } else {
2664 locations->AddTemp(Location::RequiresRegister());
2665 if (!IsPowerOfTwo(abs_imm)) {
2666 locations->AddTemp(Location::RequiresRegister());
2667 }
2668 }
2669 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002670 locations->SetInAt(0, Location::RequiresRegister());
2671 locations->SetInAt(1, Location::RequiresRegister());
2672 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2673 locations->AddTemp(Location::RequiresRegister());
2674 } else {
2675 InvokeRuntimeCallingConvention calling_convention;
2676 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2677 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2678 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2679 // we only need the latter.
2680 locations->SetOut(Location::RegisterLocation(R1));
2681 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002682 break;
2683 }
2684 case Primitive::kPrimLong: {
2685 InvokeRuntimeCallingConvention calling_convention;
2686 locations->SetInAt(0, Location::RegisterPairLocation(
2687 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2688 locations->SetInAt(1, Location::RegisterPairLocation(
2689 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2690 // The runtime helper puts the output in R2,R3.
2691 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2692 break;
2693 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002694 case Primitive::kPrimFloat: {
2695 InvokeRuntimeCallingConvention calling_convention;
2696 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2697 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2698 locations->SetOut(Location::FpuRegisterLocation(S0));
2699 break;
2700 }
2701
Calin Juravlebacfec32014-11-14 15:54:36 +00002702 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002703 InvokeRuntimeCallingConvention calling_convention;
2704 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2705 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2706 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2707 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2708 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002709 break;
2710 }
2711
2712 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002713 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002714 }
2715}
2716
2717void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2718 LocationSummary* locations = rem->GetLocations();
2719 Location out = locations->Out();
2720 Location first = locations->InAt(0);
2721 Location second = locations->InAt(1);
2722
Calin Juravled2ec87d2014-12-08 14:24:46 +00002723 Primitive::Type type = rem->GetResultType();
2724 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002725 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002726 if (second.IsConstant()) {
2727 GenerateDivRemConstantIntegral(rem);
2728 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002729 Register reg1 = first.AsRegister<Register>();
2730 Register reg2 = second.AsRegister<Register>();
2731 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002732
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002733 // temp = reg1 / reg2 (integer division)
2734 // temp = temp * reg2
2735 // dest = reg1 - temp
2736 __ sdiv(temp, reg1, reg2);
2737 __ mul(temp, temp, reg2);
2738 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2739 } else {
2740 InvokeRuntimeCallingConvention calling_convention;
2741 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2742 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2743 DCHECK_EQ(R1, out.AsRegister<Register>());
2744
2745 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2746 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002747 break;
2748 }
2749
2750 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002751 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002752 break;
2753 }
2754
Calin Juravled2ec87d2014-12-08 14:24:46 +00002755 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002756 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002757 break;
2758 }
2759
Calin Juravlebacfec32014-11-14 15:54:36 +00002760 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002761 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002762 break;
2763 }
2764
2765 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002766 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002767 }
2768}
2769
Calin Juravled0d48522014-11-04 16:40:20 +00002770void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2771 LocationSummary* locations =
2772 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002773 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002774 if (instruction->HasUses()) {
2775 locations->SetOut(Location::SameAsFirstInput());
2776 }
2777}
2778
2779void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2780 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2781 codegen_->AddSlowPath(slow_path);
2782
2783 LocationSummary* locations = instruction->GetLocations();
2784 Location value = locations->InAt(0);
2785
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002786 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002787 case Primitive::kPrimByte:
2788 case Primitive::kPrimChar:
2789 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002790 case Primitive::kPrimInt: {
2791 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002792 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002793 } else {
2794 DCHECK(value.IsConstant()) << value;
2795 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2796 __ b(slow_path->GetEntryLabel());
2797 }
2798 }
2799 break;
2800 }
2801 case Primitive::kPrimLong: {
2802 if (value.IsRegisterPair()) {
2803 __ orrs(IP,
2804 value.AsRegisterPairLow<Register>(),
2805 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2806 __ b(slow_path->GetEntryLabel(), EQ);
2807 } else {
2808 DCHECK(value.IsConstant()) << value;
2809 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2810 __ b(slow_path->GetEntryLabel());
2811 }
2812 }
2813 break;
2814 default:
2815 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2816 }
2817 }
Calin Juravled0d48522014-11-04 16:40:20 +00002818}
2819
Calin Juravle9aec02f2014-11-18 23:06:35 +00002820void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2821 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2822
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002823 LocationSummary* locations =
2824 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002825
2826 switch (op->GetResultType()) {
2827 case Primitive::kPrimInt: {
2828 locations->SetInAt(0, Location::RequiresRegister());
2829 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002830 // Make the output overlap, as it will be used to hold the masked
2831 // second input.
2832 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002833 break;
2834 }
2835 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002836 locations->SetInAt(0, Location::RequiresRegister());
2837 locations->SetInAt(1, Location::RequiresRegister());
2838 locations->AddTemp(Location::RequiresRegister());
2839 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002840 break;
2841 }
2842 default:
2843 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2844 }
2845}
2846
2847void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2848 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2849
2850 LocationSummary* locations = op->GetLocations();
2851 Location out = locations->Out();
2852 Location first = locations->InAt(0);
2853 Location second = locations->InAt(1);
2854
2855 Primitive::Type type = op->GetResultType();
2856 switch (type) {
2857 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002858 Register out_reg = out.AsRegister<Register>();
2859 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002860 // Arm doesn't mask the shift count so we need to do it ourselves.
2861 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002862 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002863 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002864 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002865 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002866 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002867 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002868 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002869 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002870 }
2871 } else {
2872 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2873 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2874 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2875 __ Mov(out_reg, first_reg);
2876 } else if (op->IsShl()) {
2877 __ Lsl(out_reg, first_reg, shift_value);
2878 } else if (op->IsShr()) {
2879 __ Asr(out_reg, first_reg, shift_value);
2880 } else {
2881 __ Lsr(out_reg, first_reg, shift_value);
2882 }
2883 }
2884 break;
2885 }
2886 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002887 Register o_h = out.AsRegisterPairHigh<Register>();
2888 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002889
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002890 Register temp = locations->GetTemp(0).AsRegister<Register>();
2891
2892 Register high = first.AsRegisterPairHigh<Register>();
2893 Register low = first.AsRegisterPairLow<Register>();
2894
2895 Register second_reg = second.AsRegister<Register>();
2896
Calin Juravle9aec02f2014-11-18 23:06:35 +00002897 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002898 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002899 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002900 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002901 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002902 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002903 __ Lsr(temp, low, temp);
2904 __ orr(o_h, o_h, ShifterOperand(temp));
2905 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002906 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002907 __ it(PL);
2908 __ Lsl(o_h, low, temp, false, PL);
2909 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002910 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002911 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002912 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002913 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002914 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002915 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002916 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002917 __ Lsl(temp, high, temp);
2918 __ orr(o_l, o_l, ShifterOperand(temp));
2919 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002920 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002921 __ it(PL);
2922 __ Asr(o_l, high, temp, false, PL);
2923 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002924 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002925 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002926 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002927 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002928 __ Lsr(o_l, low, o_h);
2929 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002930 __ Lsl(temp, high, temp);
2931 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002932 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002933 __ it(PL);
2934 __ Lsr(o_l, high, temp, false, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002935 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002936 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002937 break;
2938 }
2939 default:
2940 LOG(FATAL) << "Unexpected operation type " << type;
2941 }
2942}
2943
2944void LocationsBuilderARM::VisitShl(HShl* shl) {
2945 HandleShift(shl);
2946}
2947
2948void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2949 HandleShift(shl);
2950}
2951
2952void LocationsBuilderARM::VisitShr(HShr* shr) {
2953 HandleShift(shr);
2954}
2955
2956void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2957 HandleShift(shr);
2958}
2959
2960void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2961 HandleShift(ushr);
2962}
2963
2964void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2965 HandleShift(ushr);
2966}
2967
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002968void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002969 LocationSummary* locations =
2970 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002971 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002972 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01002973 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002974 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002975}
2976
2977void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2978 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002979 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01002980 // Note: if heap poisoning is enabled, the entry point takes cares
2981 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002982 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2983 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002984 instruction->GetDexPc(),
2985 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002986}
2987
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002988void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2989 LocationSummary* locations =
2990 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2991 InvokeRuntimeCallingConvention calling_convention;
2992 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002993 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002994 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01002995 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002996}
2997
2998void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2999 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003000 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003001 // Note: if heap poisoning is enabled, the entry point takes cares
3002 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003003 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
3004 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003005 instruction->GetDexPc(),
3006 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003007}
3008
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003009void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003010 LocationSummary* locations =
3011 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003012 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3013 if (location.IsStackSlot()) {
3014 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3015 } else if (location.IsDoubleStackSlot()) {
3016 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003017 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003018 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003019}
3020
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003021void InstructionCodeGeneratorARM::VisitParameterValue(
3022 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003023 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003024}
3025
3026void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3027 LocationSummary* locations =
3028 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3029 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3030}
3031
3032void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3033 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003034}
3035
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003036void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003037 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003038 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003039 locations->SetInAt(0, Location::RequiresRegister());
3040 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003041}
3042
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003043void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3044 LocationSummary* locations = not_->GetLocations();
3045 Location out = locations->Out();
3046 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003047 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003048 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003049 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003050 break;
3051
3052 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003053 __ mvn(out.AsRegisterPairLow<Register>(),
3054 ShifterOperand(in.AsRegisterPairLow<Register>()));
3055 __ mvn(out.AsRegisterPairHigh<Register>(),
3056 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003057 break;
3058
3059 default:
3060 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3061 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003062}
3063
David Brazdil66d126e2015-04-03 16:02:44 +01003064void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3065 LocationSummary* locations =
3066 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3067 locations->SetInAt(0, Location::RequiresRegister());
3068 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3069}
3070
3071void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003072 LocationSummary* locations = bool_not->GetLocations();
3073 Location out = locations->Out();
3074 Location in = locations->InAt(0);
3075 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3076}
3077
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003078void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003079 LocationSummary* locations =
3080 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003081 switch (compare->InputAt(0)->GetType()) {
3082 case Primitive::kPrimLong: {
3083 locations->SetInAt(0, Location::RequiresRegister());
3084 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003085 // Output overlaps because it is written before doing the low comparison.
3086 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003087 break;
3088 }
3089 case Primitive::kPrimFloat:
3090 case Primitive::kPrimDouble: {
3091 locations->SetInAt(0, Location::RequiresFpuRegister());
3092 locations->SetInAt(1, Location::RequiresFpuRegister());
3093 locations->SetOut(Location::RequiresRegister());
3094 break;
3095 }
3096 default:
3097 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3098 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003099}
3100
3101void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003102 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003103 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003104 Location left = locations->InAt(0);
3105 Location right = locations->InAt(1);
3106
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003107 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003108 Primitive::Type type = compare->InputAt(0)->GetType();
3109 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003110 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003111 __ cmp(left.AsRegisterPairHigh<Register>(),
3112 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003113 __ b(&less, LT);
3114 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003115 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003116 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003117 __ cmp(left.AsRegisterPairLow<Register>(),
3118 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003119 break;
3120 }
3121 case Primitive::kPrimFloat:
3122 case Primitive::kPrimDouble: {
3123 __ LoadImmediate(out, 0);
3124 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003125 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003126 } else {
3127 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3128 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3129 }
3130 __ vmstat(); // transfer FP status register to ARM APSR.
3131 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003132 break;
3133 }
3134 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003135 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003136 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003137 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003138 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003139
3140 __ Bind(&greater);
3141 __ LoadImmediate(out, 1);
3142 __ b(&done);
3143
3144 __ Bind(&less);
3145 __ LoadImmediate(out, -1);
3146
3147 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003148}
3149
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003150void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003151 LocationSummary* locations =
3152 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003153 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3154 locations->SetInAt(i, Location::Any());
3155 }
3156 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003157}
3158
3159void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003160 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003161 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003162}
3163
Calin Juravle52c48962014-12-16 17:02:57 +00003164void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3165 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003166 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003167 switch (kind) {
3168 case MemBarrierKind::kAnyStore:
3169 case MemBarrierKind::kLoadAny:
3170 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003171 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003172 break;
3173 }
3174 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003175 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003176 break;
3177 }
3178 default:
3179 LOG(FATAL) << "Unexpected memory barrier " << kind;
3180 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003181 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003182}
3183
3184void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3185 uint32_t offset,
3186 Register out_lo,
3187 Register out_hi) {
3188 if (offset != 0) {
3189 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003190 __ add(IP, addr, ShifterOperand(out_lo));
3191 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003192 }
3193 __ ldrexd(out_lo, out_hi, addr);
3194}
3195
3196void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3197 uint32_t offset,
3198 Register value_lo,
3199 Register value_hi,
3200 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003201 Register temp2,
3202 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003203 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003204 if (offset != 0) {
3205 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003206 __ add(IP, addr, ShifterOperand(temp1));
3207 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003208 }
3209 __ Bind(&fail);
3210 // We need a load followed by store. (The address used in a STREX instruction must
3211 // be the same as the address in the most recently executed LDREX instruction.)
3212 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003213 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003214 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003215 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003216}
3217
3218void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3219 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3220
Nicolas Geoffray39468442014-09-02 15:17:15 +01003221 LocationSummary* locations =
3222 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003223 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003224
Calin Juravle52c48962014-12-16 17:02:57 +00003225 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003226 if (Primitive::IsFloatingPointType(field_type)) {
3227 locations->SetInAt(1, Location::RequiresFpuRegister());
3228 } else {
3229 locations->SetInAt(1, Location::RequiresRegister());
3230 }
3231
Calin Juravle52c48962014-12-16 17:02:57 +00003232 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003233 bool generate_volatile = field_info.IsVolatile()
3234 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003235 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003236 bool needs_write_barrier =
3237 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003238 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003239 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003240 if (needs_write_barrier) {
3241 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003242 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003243 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003244 // Arm encoding have some additional constraints for ldrexd/strexd:
3245 // - registers need to be consecutive
3246 // - the first register should be even but not R14.
3247 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3248 // enable Arm encoding.
3249 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3250
3251 locations->AddTemp(Location::RequiresRegister());
3252 locations->AddTemp(Location::RequiresRegister());
3253 if (field_type == Primitive::kPrimDouble) {
3254 // For doubles we need two more registers to copy the value.
3255 locations->AddTemp(Location::RegisterLocation(R2));
3256 locations->AddTemp(Location::RegisterLocation(R3));
3257 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003258 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003259}
3260
Calin Juravle52c48962014-12-16 17:02:57 +00003261void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003262 const FieldInfo& field_info,
3263 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003264 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3265
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003266 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003267 Register base = locations->InAt(0).AsRegister<Register>();
3268 Location value = locations->InAt(1);
3269
3270 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003271 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003272 Primitive::Type field_type = field_info.GetFieldType();
3273 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003274 bool needs_write_barrier =
3275 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003276
3277 if (is_volatile) {
3278 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3279 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003280
3281 switch (field_type) {
3282 case Primitive::kPrimBoolean:
3283 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003284 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003285 break;
3286 }
3287
3288 case Primitive::kPrimShort:
3289 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003290 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003291 break;
3292 }
3293
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003294 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003295 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003296 if (kPoisonHeapReferences && needs_write_barrier) {
3297 // Note that in the case where `value` is a null reference,
3298 // we do not enter this block, as a null reference does not
3299 // need poisoning.
3300 DCHECK_EQ(field_type, Primitive::kPrimNot);
3301 Register temp = locations->GetTemp(0).AsRegister<Register>();
3302 __ Mov(temp, value.AsRegister<Register>());
3303 __ PoisonHeapReference(temp);
3304 __ StoreToOffset(kStoreWord, temp, base, offset);
3305 } else {
3306 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3307 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003308 break;
3309 }
3310
3311 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003312 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003313 GenerateWideAtomicStore(base, offset,
3314 value.AsRegisterPairLow<Register>(),
3315 value.AsRegisterPairHigh<Register>(),
3316 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003317 locations->GetTemp(1).AsRegister<Register>(),
3318 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003319 } else {
3320 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003321 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003322 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003323 break;
3324 }
3325
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003326 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003327 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003328 break;
3329 }
3330
3331 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003332 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003333 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003334 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3335 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3336
3337 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3338
3339 GenerateWideAtomicStore(base, offset,
3340 value_reg_lo,
3341 value_reg_hi,
3342 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003343 locations->GetTemp(3).AsRegister<Register>(),
3344 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003345 } else {
3346 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003347 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003348 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003349 break;
3350 }
3351
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003352 case Primitive::kPrimVoid:
3353 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003354 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003355 }
Calin Juravle52c48962014-12-16 17:02:57 +00003356
Calin Juravle77520bc2015-01-12 18:45:46 +00003357 // Longs and doubles are handled in the switch.
3358 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3359 codegen_->MaybeRecordImplicitNullCheck(instruction);
3360 }
3361
3362 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3363 Register temp = locations->GetTemp(0).AsRegister<Register>();
3364 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003365 codegen_->MarkGCCard(
3366 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003367 }
3368
Calin Juravle52c48962014-12-16 17:02:57 +00003369 if (is_volatile) {
3370 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3371 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003372}
3373
Calin Juravle52c48962014-12-16 17:02:57 +00003374void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3375 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003376 LocationSummary* locations =
3377 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003378 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003379
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003380 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003381 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003382 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003383 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003384
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003385 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3386 locations->SetOut(Location::RequiresFpuRegister());
3387 } else {
3388 locations->SetOut(Location::RequiresRegister(),
3389 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3390 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003391 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003392 // Arm encoding have some additional constraints for ldrexd/strexd:
3393 // - registers need to be consecutive
3394 // - the first register should be even but not R14.
3395 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3396 // enable Arm encoding.
3397 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3398 locations->AddTemp(Location::RequiresRegister());
3399 locations->AddTemp(Location::RequiresRegister());
3400 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003401}
3402
Calin Juravle52c48962014-12-16 17:02:57 +00003403void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3404 const FieldInfo& field_info) {
3405 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003406
Calin Juravle52c48962014-12-16 17:02:57 +00003407 LocationSummary* locations = instruction->GetLocations();
3408 Register base = locations->InAt(0).AsRegister<Register>();
3409 Location out = locations->Out();
3410 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003411 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003412 Primitive::Type field_type = field_info.GetFieldType();
3413 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3414
3415 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003416 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003417 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003418 break;
3419 }
3420
3421 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003422 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003423 break;
3424 }
3425
3426 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003427 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003428 break;
3429 }
3430
3431 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003432 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003433 break;
3434 }
3435
3436 case Primitive::kPrimInt:
3437 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003438 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003439 break;
3440 }
3441
3442 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003443 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003444 GenerateWideAtomicLoad(base, offset,
3445 out.AsRegisterPairLow<Register>(),
3446 out.AsRegisterPairHigh<Register>());
3447 } else {
3448 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3449 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003450 break;
3451 }
3452
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003453 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003454 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003455 break;
3456 }
3457
3458 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003459 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003460 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003461 Register lo = locations->GetTemp(0).AsRegister<Register>();
3462 Register hi = locations->GetTemp(1).AsRegister<Register>();
3463 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003464 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003465 __ vmovdrr(out_reg, lo, hi);
3466 } else {
3467 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003468 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003469 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003470 break;
3471 }
3472
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003473 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003474 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003475 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003476 }
Calin Juravle52c48962014-12-16 17:02:57 +00003477
Calin Juravle77520bc2015-01-12 18:45:46 +00003478 // Doubles are handled in the switch.
3479 if (field_type != Primitive::kPrimDouble) {
3480 codegen_->MaybeRecordImplicitNullCheck(instruction);
3481 }
3482
Calin Juravle52c48962014-12-16 17:02:57 +00003483 if (is_volatile) {
3484 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3485 }
Roland Levillain4d027112015-07-01 15:41:14 +01003486
3487 if (field_type == Primitive::kPrimNot) {
3488 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3489 }
Calin Juravle52c48962014-12-16 17:02:57 +00003490}
3491
3492void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3493 HandleFieldSet(instruction, instruction->GetFieldInfo());
3494}
3495
3496void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003497 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003498}
3499
3500void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3501 HandleFieldGet(instruction, instruction->GetFieldInfo());
3502}
3503
3504void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3505 HandleFieldGet(instruction, instruction->GetFieldInfo());
3506}
3507
3508void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3509 HandleFieldGet(instruction, instruction->GetFieldInfo());
3510}
3511
3512void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3513 HandleFieldGet(instruction, instruction->GetFieldInfo());
3514}
3515
3516void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3517 HandleFieldSet(instruction, instruction->GetFieldInfo());
3518}
3519
3520void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003521 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003522}
3523
3524void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003525 LocationSummary* locations =
3526 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003527 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003528 if (instruction->HasUses()) {
3529 locations->SetOut(Location::SameAsFirstInput());
3530 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003531}
3532
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003533void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003534 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3535 return;
3536 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003537 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003538
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003539 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3540 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3541}
3542
3543void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003544 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003545 codegen_->AddSlowPath(slow_path);
3546
3547 LocationSummary* locations = instruction->GetLocations();
3548 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003549
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003550 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003551}
3552
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003553void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3554 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3555 GenerateImplicitNullCheck(instruction);
3556 } else {
3557 GenerateExplicitNullCheck(instruction);
3558 }
3559}
3560
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003561void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003562 LocationSummary* locations =
3563 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003564 locations->SetInAt(0, Location::RequiresRegister());
3565 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003566 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3567 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3568 } else {
3569 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3570 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003571}
3572
3573void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3574 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003575 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003576 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003577 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003578
Roland Levillain4d027112015-07-01 15:41:14 +01003579 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003580 case Primitive::kPrimBoolean: {
3581 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003582 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003583 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003584 size_t offset =
3585 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003586 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3587 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003588 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003589 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3590 }
3591 break;
3592 }
3593
3594 case Primitive::kPrimByte: {
3595 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003596 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003597 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003598 size_t offset =
3599 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003600 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3601 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003602 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003603 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3604 }
3605 break;
3606 }
3607
3608 case Primitive::kPrimShort: {
3609 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003610 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003611 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003612 size_t offset =
3613 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003614 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3615 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003616 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003617 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3618 }
3619 break;
3620 }
3621
3622 case Primitive::kPrimChar: {
3623 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003624 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003625 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003626 size_t offset =
3627 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003628 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3629 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003630 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003631 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3632 }
3633 break;
3634 }
3635
3636 case Primitive::kPrimInt:
3637 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003638 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3639 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003640 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003641 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003642 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003643 size_t offset =
3644 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003645 __ LoadFromOffset(kLoadWord, out, obj, offset);
3646 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003647 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003648 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3649 }
3650 break;
3651 }
3652
3653 case Primitive::kPrimLong: {
3654 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003655 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003656 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003657 size_t offset =
3658 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003659 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003660 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003662 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003663 }
3664 break;
3665 }
3666
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003667 case Primitive::kPrimFloat: {
3668 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3669 Location out = locations->Out();
3670 DCHECK(out.IsFpuRegister());
3671 if (index.IsConstant()) {
3672 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3673 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3674 } else {
3675 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3676 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3677 }
3678 break;
3679 }
3680
3681 case Primitive::kPrimDouble: {
3682 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3683 Location out = locations->Out();
3684 DCHECK(out.IsFpuRegisterPair());
3685 if (index.IsConstant()) {
3686 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3687 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3688 } else {
3689 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3690 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3691 }
3692 break;
3693 }
3694
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003695 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003696 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003697 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003698 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003699 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003700
3701 if (type == Primitive::kPrimNot) {
3702 Register out = locations->Out().AsRegister<Register>();
3703 __ MaybeUnpoisonHeapReference(out);
3704 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003705}
3706
3707void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003708 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003709
3710 bool needs_write_barrier =
3711 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3712 bool needs_runtime_call = instruction->NeedsTypeCheck();
3713
Nicolas Geoffray39468442014-09-02 15:17:15 +01003714 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003715 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3716 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003718 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3719 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3720 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003721 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003722 locations->SetInAt(0, Location::RequiresRegister());
3723 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003724 if (Primitive::IsFloatingPointType(value_type)) {
3725 locations->SetInAt(2, Location::RequiresFpuRegister());
3726 } else {
3727 locations->SetInAt(2, Location::RequiresRegister());
3728 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003729
3730 if (needs_write_barrier) {
3731 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003732 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003733 locations->AddTemp(Location::RequiresRegister());
3734 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003735 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003736}
3737
3738void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3739 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003740 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003741 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003742 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003743 bool needs_runtime_call = locations->WillCall();
3744 bool needs_write_barrier =
3745 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003746
3747 switch (value_type) {
3748 case Primitive::kPrimBoolean:
3749 case Primitive::kPrimByte: {
3750 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003751 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003752 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003753 size_t offset =
3754 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003755 __ StoreToOffset(kStoreByte, value, obj, offset);
3756 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003757 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003758 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3759 }
3760 break;
3761 }
3762
3763 case Primitive::kPrimShort:
3764 case Primitive::kPrimChar: {
3765 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003766 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003767 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003768 size_t offset =
3769 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003770 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3771 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003772 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003773 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3774 }
3775 break;
3776 }
3777
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003778 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003779 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003780 if (!needs_runtime_call) {
3781 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003782 Register value = locations->InAt(2).AsRegister<Register>();
Roland Levillain4d027112015-07-01 15:41:14 +01003783 Register source = value;
3784 if (kPoisonHeapReferences && needs_write_barrier) {
3785 // Note that in the case where `value` is a null reference,
3786 // we do not enter this block, as a null reference does not
3787 // need poisoning.
3788 DCHECK_EQ(value_type, Primitive::kPrimNot);
3789 Register temp = locations->GetTemp(0).AsRegister<Register>();
3790 __ Mov(temp, value);
3791 __ PoisonHeapReference(temp);
3792 source = temp;
3793 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003794 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003795 size_t offset =
3796 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain4d027112015-07-01 15:41:14 +01003797 __ StoreToOffset(kStoreWord, source, obj, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003798 } else {
3799 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003800 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003801 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003802 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003803 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003804 if (needs_write_barrier) {
3805 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003806 Register temp = locations->GetTemp(0).AsRegister<Register>();
3807 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003808 codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003809 }
3810 } else {
3811 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003812 // Note: if heap poisoning is enabled, pAputObject takes cares
3813 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003814 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3815 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003816 instruction->GetDexPc(),
3817 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003818 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003819 break;
3820 }
3821
3822 case Primitive::kPrimLong: {
3823 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003824 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003825 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003826 size_t offset =
3827 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003828 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003829 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003830 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003831 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003832 }
3833 break;
3834 }
3835
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003836 case Primitive::kPrimFloat: {
3837 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3838 Location value = locations->InAt(2);
3839 DCHECK(value.IsFpuRegister());
3840 if (index.IsConstant()) {
3841 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3842 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3843 } else {
3844 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3845 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3846 }
3847 break;
3848 }
3849
3850 case Primitive::kPrimDouble: {
3851 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3852 Location value = locations->InAt(2);
3853 DCHECK(value.IsFpuRegisterPair());
3854 if (index.IsConstant()) {
3855 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3856 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3857 } else {
3858 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3859 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3860 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003861
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003862 break;
3863 }
3864
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003865 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003866 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003867 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003868 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003869
3870 // Ints and objects are handled in the switch.
3871 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3872 codegen_->MaybeRecordImplicitNullCheck(instruction);
3873 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003874}
3875
3876void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003877 LocationSummary* locations =
3878 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003879 locations->SetInAt(0, Location::RequiresRegister());
3880 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003881}
3882
3883void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3884 LocationSummary* locations = instruction->GetLocations();
3885 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003886 Register obj = locations->InAt(0).AsRegister<Register>();
3887 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003888 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003889 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003890}
3891
3892void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003893 LocationSummary* locations =
3894 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003895 locations->SetInAt(0, Location::RequiresRegister());
3896 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003897 if (instruction->HasUses()) {
3898 locations->SetOut(Location::SameAsFirstInput());
3899 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003900}
3901
3902void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3903 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003904 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003905 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003906 codegen_->AddSlowPath(slow_path);
3907
Roland Levillain271ab9c2014-11-27 15:23:57 +00003908 Register index = locations->InAt(0).AsRegister<Register>();
3909 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003910
3911 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01003912 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003913}
3914
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003915void CodeGeneratorARM::MarkGCCard(Register temp,
3916 Register card,
3917 Register object,
3918 Register value,
3919 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003920 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003921 if (can_be_null) {
3922 __ CompareAndBranchIfZero(value, &is_null);
3923 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003924 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3925 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3926 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003927 if (can_be_null) {
3928 __ Bind(&is_null);
3929 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003930}
3931
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003932void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3933 temp->SetLocations(nullptr);
3934}
3935
3936void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3937 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003938 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003939}
3940
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003941void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003942 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003943 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003944}
3945
3946void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003947 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3948}
3949
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003950void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3951 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3952}
3953
3954void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003955 HBasicBlock* block = instruction->GetBlock();
3956 if (block->GetLoopInformation() != nullptr) {
3957 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3958 // The back edge will generate the suspend check.
3959 return;
3960 }
3961 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3962 // The goto will generate the suspend check.
3963 return;
3964 }
3965 GenerateSuspendCheck(instruction, nullptr);
3966}
3967
3968void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3969 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003970 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003971 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
3972 if (slow_path == nullptr) {
3973 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
3974 instruction->SetSlowPath(slow_path);
3975 codegen_->AddSlowPath(slow_path);
3976 if (successor != nullptr) {
3977 DCHECK(successor->IsLoopHeader());
3978 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3979 }
3980 } else {
3981 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3982 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003983
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003984 __ LoadFromOffset(
3985 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003986 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003987 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003988 __ Bind(slow_path->GetReturnLabel());
3989 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003990 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003991 __ b(slow_path->GetEntryLabel());
3992 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003993}
3994
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003995ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3996 return codegen_->GetAssembler();
3997}
3998
3999void ParallelMoveResolverARM::EmitMove(size_t index) {
4000 MoveOperands* move = moves_.Get(index);
4001 Location source = move->GetSource();
4002 Location destination = move->GetDestination();
4003
4004 if (source.IsRegister()) {
4005 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004006 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004007 } else {
4008 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004009 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004010 SP, destination.GetStackIndex());
4011 }
4012 } else if (source.IsStackSlot()) {
4013 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004014 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004015 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004016 } else if (destination.IsFpuRegister()) {
4017 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004018 } else {
4019 DCHECK(destination.IsStackSlot());
4020 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4021 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4022 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004023 } else if (source.IsFpuRegister()) {
4024 if (destination.IsFpuRegister()) {
4025 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004026 } else {
4027 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004028 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4029 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004030 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004031 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004032 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4033 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004034 } else if (destination.IsRegisterPair()) {
4035 DCHECK(ExpectedPairLayout(destination));
4036 __ LoadFromOffset(
4037 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4038 } else {
4039 DCHECK(destination.IsFpuRegisterPair()) << destination;
4040 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4041 SP,
4042 source.GetStackIndex());
4043 }
4044 } else if (source.IsRegisterPair()) {
4045 if (destination.IsRegisterPair()) {
4046 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4047 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4048 } else {
4049 DCHECK(destination.IsDoubleStackSlot()) << destination;
4050 DCHECK(ExpectedPairLayout(source));
4051 __ StoreToOffset(
4052 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4053 }
4054 } else if (source.IsFpuRegisterPair()) {
4055 if (destination.IsFpuRegisterPair()) {
4056 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4057 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4058 } else {
4059 DCHECK(destination.IsDoubleStackSlot()) << destination;
4060 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4061 SP,
4062 destination.GetStackIndex());
4063 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004064 } else {
4065 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004066 HConstant* constant = source.GetConstant();
4067 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4068 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004069 if (destination.IsRegister()) {
4070 __ LoadImmediate(destination.AsRegister<Register>(), value);
4071 } else {
4072 DCHECK(destination.IsStackSlot());
4073 __ LoadImmediate(IP, value);
4074 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4075 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004076 } else if (constant->IsLongConstant()) {
4077 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004078 if (destination.IsRegisterPair()) {
4079 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4080 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004081 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004082 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004083 __ LoadImmediate(IP, Low32Bits(value));
4084 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4085 __ LoadImmediate(IP, High32Bits(value));
4086 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4087 }
4088 } else if (constant->IsDoubleConstant()) {
4089 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004090 if (destination.IsFpuRegisterPair()) {
4091 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004092 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004093 DCHECK(destination.IsDoubleStackSlot()) << destination;
4094 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004095 __ LoadImmediate(IP, Low32Bits(int_value));
4096 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4097 __ LoadImmediate(IP, High32Bits(int_value));
4098 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4099 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004100 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004101 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004102 float value = constant->AsFloatConstant()->GetValue();
4103 if (destination.IsFpuRegister()) {
4104 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4105 } else {
4106 DCHECK(destination.IsStackSlot());
4107 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4108 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4109 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004110 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004111 }
4112}
4113
4114void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4115 __ Mov(IP, reg);
4116 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4117 __ StoreToOffset(kStoreWord, IP, SP, mem);
4118}
4119
4120void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4121 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4122 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4123 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4124 SP, mem1 + stack_offset);
4125 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4126 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4127 SP, mem2 + stack_offset);
4128 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4129}
4130
4131void ParallelMoveResolverARM::EmitSwap(size_t index) {
4132 MoveOperands* move = moves_.Get(index);
4133 Location source = move->GetSource();
4134 Location destination = move->GetDestination();
4135
4136 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004137 DCHECK_NE(source.AsRegister<Register>(), IP);
4138 DCHECK_NE(destination.AsRegister<Register>(), IP);
4139 __ Mov(IP, source.AsRegister<Register>());
4140 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4141 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004142 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004143 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004144 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004145 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004146 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4147 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004148 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004149 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004150 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004151 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004152 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004153 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004154 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004155 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004156 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4157 destination.AsRegisterPairHigh<Register>(),
4158 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004159 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004160 Register low_reg = source.IsRegisterPair()
4161 ? source.AsRegisterPairLow<Register>()
4162 : destination.AsRegisterPairLow<Register>();
4163 int mem = source.IsRegisterPair()
4164 ? destination.GetStackIndex()
4165 : source.GetStackIndex();
4166 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004167 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004168 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004169 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004170 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004171 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4172 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004173 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004174 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004175 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004176 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4177 DRegister reg = source.IsFpuRegisterPair()
4178 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4179 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4180 int mem = source.IsFpuRegisterPair()
4181 ? destination.GetStackIndex()
4182 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004183 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004184 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004185 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004186 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4187 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4188 : destination.AsFpuRegister<SRegister>();
4189 int mem = source.IsFpuRegister()
4190 ? destination.GetStackIndex()
4191 : source.GetStackIndex();
4192
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004193 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004194 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004195 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004196 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004197 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4198 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004199 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004200 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004201 }
4202}
4203
4204void ParallelMoveResolverARM::SpillScratch(int reg) {
4205 __ Push(static_cast<Register>(reg));
4206}
4207
4208void ParallelMoveResolverARM::RestoreScratch(int reg) {
4209 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004210}
4211
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004212void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004213 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4214 ? LocationSummary::kCallOnSlowPath
4215 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004216 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004217 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004218 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004219 locations->SetOut(Location::RequiresRegister());
4220}
4221
4222void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004223 LocationSummary* locations = cls->GetLocations();
4224 Register out = locations->Out().AsRegister<Register>();
4225 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004226 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004227 DCHECK(!cls->CanCallRuntime());
4228 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004229 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004230 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004231 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004232 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004233 __ LoadFromOffset(kLoadWord,
4234 out,
4235 current_method,
Mathieu Chartiere401d142015-04-22 13:56:20 -07004236 ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004237 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01004238 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004239
4240 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
4241 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4242 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004243 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004244 if (cls->MustGenerateClinitCheck()) {
4245 GenerateClassInitializationCheck(slow_path, out);
4246 } else {
4247 __ Bind(slow_path->GetExitLabel());
4248 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004249 }
4250}
4251
4252void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4253 LocationSummary* locations =
4254 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4255 locations->SetInAt(0, Location::RequiresRegister());
4256 if (check->HasUses()) {
4257 locations->SetOut(Location::SameAsFirstInput());
4258 }
4259}
4260
4261void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004262 // We assume the class is not null.
4263 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
4264 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004265 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004266 GenerateClassInitializationCheck(slow_path,
4267 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004268}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004269
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004270void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
4271 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004272 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4273 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4274 __ b(slow_path->GetEntryLabel(), LT);
4275 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4276 // properly. Therefore, we do a memory fence.
4277 __ dmb(ISH);
4278 __ Bind(slow_path->GetExitLabel());
4279}
4280
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004281void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4282 LocationSummary* locations =
4283 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004284 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004285 locations->SetOut(Location::RequiresRegister());
4286}
4287
4288void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
4289 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
4290 codegen_->AddSlowPath(slow_path);
4291
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004292 LocationSummary* locations = load->GetLocations();
4293 Register out = locations->Out().AsRegister<Register>();
4294 Register current_method = locations->InAt(0).AsRegister<Register>();
4295 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004296 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004297 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01004298 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004299 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01004300 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004301 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004302 __ Bind(slow_path->GetExitLabel());
4303}
4304
David Brazdilcb1c0552015-08-04 16:22:25 +01004305static int32_t GetExceptionTlsOffset() {
4306 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4307}
4308
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004309void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4310 LocationSummary* locations =
4311 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4312 locations->SetOut(Location::RequiresRegister());
4313}
4314
4315void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004316 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004317 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4318}
4319
4320void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4321 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4322}
4323
4324void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004325 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004326 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004327}
4328
4329void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4330 LocationSummary* locations =
4331 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4332 InvokeRuntimeCallingConvention calling_convention;
4333 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4334}
4335
4336void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4337 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004338 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004339}
4340
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004341void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004342 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4343 ? LocationSummary::kNoCall
4344 : LocationSummary::kCallOnSlowPath;
4345 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4346 locations->SetInAt(0, Location::RequiresRegister());
4347 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004348 // The out register is used as a temporary, so it overlaps with the inputs.
4349 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004350}
4351
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004352void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004353 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004354 Register obj = locations->InAt(0).AsRegister<Register>();
4355 Register cls = locations->InAt(1).AsRegister<Register>();
4356 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004357 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004358 Label done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004359 SlowPathCodeARM* slow_path = nullptr;
4360
4361 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004362 // avoid null check if we know obj is not null.
4363 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004364 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004365 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004366 // Compare the class of `obj` with `cls`.
4367 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004368 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004369 __ cmp(out, ShifterOperand(cls));
4370 if (instruction->IsClassFinal()) {
4371 // Classes must be equal for the instanceof to succeed.
4372 __ b(&zero, NE);
4373 __ LoadImmediate(out, 1);
4374 __ b(&done);
4375 } else {
4376 // If the classes are not equal, we go into a slow path.
4377 DCHECK(locations->OnlyCallsOnSlowPath());
4378 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004379 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004380 codegen_->AddSlowPath(slow_path);
4381 __ b(slow_path->GetEntryLabel(), NE);
4382 __ LoadImmediate(out, 1);
4383 __ b(&done);
4384 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004385
4386 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4387 __ Bind(&zero);
4388 __ LoadImmediate(out, 0);
4389 }
4390
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004391 if (slow_path != nullptr) {
4392 __ Bind(slow_path->GetExitLabel());
4393 }
4394 __ Bind(&done);
4395}
4396
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004397void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
4398 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4399 instruction, LocationSummary::kCallOnSlowPath);
4400 locations->SetInAt(0, Location::RequiresRegister());
4401 locations->SetInAt(1, Location::RequiresRegister());
4402 locations->AddTemp(Location::RequiresRegister());
4403}
4404
4405void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4406 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004407 Register obj = locations->InAt(0).AsRegister<Register>();
4408 Register cls = locations->InAt(1).AsRegister<Register>();
4409 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004410 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4411
4412 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4413 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4414 codegen_->AddSlowPath(slow_path);
4415
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004416 // avoid null check if we know obj is not null.
4417 if (instruction->MustDoNullCheck()) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004418 __ CompareAndBranchIfZero(obj, slow_path->GetExitLabel());
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004419 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004420 // Compare the class of `obj` with `cls`.
4421 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004422 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004423 __ cmp(temp, ShifterOperand(cls));
Roland Levillain4d027112015-07-01 15:41:14 +01004424 // The checkcast succeeds if the classes are equal (fast path).
4425 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004426 __ b(slow_path->GetEntryLabel(), NE);
4427 __ Bind(slow_path->GetExitLabel());
4428}
4429
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004430void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4431 LocationSummary* locations =
4432 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4433 InvokeRuntimeCallingConvention calling_convention;
4434 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4435}
4436
4437void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4438 codegen_->InvokeRuntime(instruction->IsEnter()
4439 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4440 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004441 instruction->GetDexPc(),
4442 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004443}
4444
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004445void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4446void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4447void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4448
4449void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4450 LocationSummary* locations =
4451 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4452 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4453 || instruction->GetResultType() == Primitive::kPrimLong);
4454 locations->SetInAt(0, Location::RequiresRegister());
4455 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004456 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004457}
4458
4459void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4460 HandleBitwiseOperation(instruction);
4461}
4462
4463void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4464 HandleBitwiseOperation(instruction);
4465}
4466
4467void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4468 HandleBitwiseOperation(instruction);
4469}
4470
4471void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4472 LocationSummary* locations = instruction->GetLocations();
4473
4474 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004475 Register first = locations->InAt(0).AsRegister<Register>();
4476 Register second = locations->InAt(1).AsRegister<Register>();
4477 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004478 if (instruction->IsAnd()) {
4479 __ and_(out, first, ShifterOperand(second));
4480 } else if (instruction->IsOr()) {
4481 __ orr(out, first, ShifterOperand(second));
4482 } else {
4483 DCHECK(instruction->IsXor());
4484 __ eor(out, first, ShifterOperand(second));
4485 }
4486 } else {
4487 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4488 Location first = locations->InAt(0);
4489 Location second = locations->InAt(1);
4490 Location out = locations->Out();
4491 if (instruction->IsAnd()) {
4492 __ and_(out.AsRegisterPairLow<Register>(),
4493 first.AsRegisterPairLow<Register>(),
4494 ShifterOperand(second.AsRegisterPairLow<Register>()));
4495 __ and_(out.AsRegisterPairHigh<Register>(),
4496 first.AsRegisterPairHigh<Register>(),
4497 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4498 } else if (instruction->IsOr()) {
4499 __ orr(out.AsRegisterPairLow<Register>(),
4500 first.AsRegisterPairLow<Register>(),
4501 ShifterOperand(second.AsRegisterPairLow<Register>()));
4502 __ orr(out.AsRegisterPairHigh<Register>(),
4503 first.AsRegisterPairHigh<Register>(),
4504 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4505 } else {
4506 DCHECK(instruction->IsXor());
4507 __ eor(out.AsRegisterPairLow<Register>(),
4508 first.AsRegisterPairLow<Register>(),
4509 ShifterOperand(second.AsRegisterPairLow<Register>()));
4510 __ eor(out.AsRegisterPairHigh<Register>(),
4511 first.AsRegisterPairHigh<Register>(),
4512 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4513 }
4514 }
4515}
4516
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004517void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004518 // For better instruction scheduling we load the direct code pointer before the method pointer.
4519 bool direct_code_loaded = false;
4520 switch (invoke->GetCodePtrLocation()) {
4521 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4522 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4523 break;
4524 }
4525 // Calls across dex files are more likely to exceed the available BL range,
4526 // so use absolute patch by falling through to kDirectCodeFixup.
4527 FALLTHROUGH_INTENDED;
4528 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4529 // LR = code address from literal pool with link-time patch.
4530 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4531 direct_code_loaded = true;
4532 break;
4533 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4534 // LR = invoke->GetDirectCodePtr();
4535 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4536 direct_code_loaded = true;
4537 break;
4538 default:
4539 break;
4540 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004541
Vladimir Marko58155012015-08-19 12:49:41 +00004542 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4543 switch (invoke->GetMethodLoadKind()) {
4544 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
4545 // temp = thread->string_init_entrypoint
4546 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
4547 break;
4548 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4549 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4550 break;
4551 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4552 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4553 break;
4554 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4555 __ LoadLiteral(temp.AsRegister<Register>(),
4556 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4557 break;
4558 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
4559 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
4560 FALLTHROUGH_INTENDED;
4561 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4562 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4563 Register method_reg;
4564 Register reg = temp.AsRegister<Register>();
4565 if (current_method.IsRegister()) {
4566 method_reg = current_method.AsRegister<Register>();
4567 } else {
4568 DCHECK(invoke->GetLocations()->Intrinsified());
4569 DCHECK(!current_method.IsValid());
4570 method_reg = reg;
4571 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
4572 }
4573 // temp = current_method->dex_cache_resolved_methods_;
4574 __ LoadFromOffset(
4575 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
4576 // temp = temp[index_in_cache]
4577 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
4578 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
4579 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01004580 }
Vladimir Marko58155012015-08-19 12:49:41 +00004581 }
4582
4583 switch (invoke->GetCodePtrLocation()) {
4584 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
4585 __ bl(GetFrameEntryLabel());
4586 break;
4587 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4588 if (!direct_code_loaded) {
4589 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
4590 __ Bind(&relative_call_patches_.back().label);
4591 Label label;
4592 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
4593 __ Bind(&label);
4594 break;
4595 }
4596 // If we loaded the direct code above, fall through.
4597 FALLTHROUGH_INTENDED;
4598 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4599 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4600 // LR prepared above for better instruction scheduling.
4601 DCHECK(direct_code_loaded);
4602 // LR()
4603 __ blx(LR);
4604 break;
4605 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4606 // LR = callee_method->entry_point_from_quick_compiled_code_
4607 __ LoadFromOffset(
4608 kLoadWord, LR, callee_method.AsRegister<Register>(),
4609 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
4610 // LR()
4611 __ blx(LR);
4612 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004613 }
4614
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004615 DCHECK(!IsLeafMethod());
4616}
4617
Vladimir Marko58155012015-08-19 12:49:41 +00004618void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
4619 DCHECK(linker_patches->empty());
4620 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
4621 linker_patches->reserve(size);
4622 for (const auto& entry : method_patches_) {
4623 const MethodReference& target_method = entry.first;
4624 Literal* literal = entry.second;
4625 DCHECK(literal->GetLabel()->IsBound());
4626 uint32_t literal_offset = literal->GetLabel()->Position();
4627 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
4628 target_method.dex_file,
4629 target_method.dex_method_index));
4630 }
4631 for (const auto& entry : call_patches_) {
4632 const MethodReference& target_method = entry.first;
4633 Literal* literal = entry.second;
4634 DCHECK(literal->GetLabel()->IsBound());
4635 uint32_t literal_offset = literal->GetLabel()->Position();
4636 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
4637 target_method.dex_file,
4638 target_method.dex_method_index));
4639 }
4640 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
4641 uint32_t literal_offset = info.label.Position();
4642 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
4643 info.target_method.dex_file,
4644 info.target_method.dex_method_index));
4645 }
4646}
4647
4648Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
4649 MethodToLiteralMap* map) {
4650 // Look up the literal for target_method.
4651 auto lb = map->lower_bound(target_method);
4652 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
4653 return lb->second;
4654 }
4655 // We don't have a literal for this method yet, insert a new one.
4656 Literal* literal = __ NewLiteral<uint32_t>(0u);
4657 map->PutBefore(lb, target_method, literal);
4658 return literal;
4659}
4660
4661Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
4662 return DeduplicateMethodLiteral(target_method, &method_patches_);
4663}
4664
4665Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
4666 return DeduplicateMethodLiteral(target_method, &call_patches_);
4667}
4668
Calin Juravleb1498f62015-02-16 13:13:29 +00004669void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4670 // Nothing to do, this should be removed during prepare for register allocator.
4671 UNUSED(instruction);
4672 LOG(FATAL) << "Unreachable";
4673}
4674
4675void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4676 // Nothing to do, this should be removed during prepare for register allocator.
4677 UNUSED(instruction);
4678 LOG(FATAL) << "Unreachable";
4679}
4680
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004681void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
4682 DCHECK(codegen_->IsBaseline());
4683 LocationSummary* locations =
4684 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4685 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4686}
4687
4688void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4689 DCHECK(codegen_->IsBaseline());
4690 // Will be generated at use site.
4691}
4692
Roland Levillain4d027112015-07-01 15:41:14 +01004693#undef __
4694#undef QUICK_ENTRY_POINT
4695
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004696} // namespace arm
4697} // namespace art