blob: 9de9abffd84f5df4e18925694dbfbfe083f95fc1 [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)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002734 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002735 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002736 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002737 } else {
2738 InvokeRuntimeCallingConvention calling_convention;
2739 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2740 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2741 DCHECK_EQ(R1, out.AsRegister<Register>());
2742
2743 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2744 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002745 break;
2746 }
2747
2748 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002749 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002750 break;
2751 }
2752
Calin Juravled2ec87d2014-12-08 14:24:46 +00002753 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002754 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002755 break;
2756 }
2757
Calin Juravlebacfec32014-11-14 15:54:36 +00002758 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002759 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002760 break;
2761 }
2762
2763 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002764 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002765 }
2766}
2767
Calin Juravled0d48522014-11-04 16:40:20 +00002768void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2769 LocationSummary* locations =
2770 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002771 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002772 if (instruction->HasUses()) {
2773 locations->SetOut(Location::SameAsFirstInput());
2774 }
2775}
2776
2777void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2778 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2779 codegen_->AddSlowPath(slow_path);
2780
2781 LocationSummary* locations = instruction->GetLocations();
2782 Location value = locations->InAt(0);
2783
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002784 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002785 case Primitive::kPrimByte:
2786 case Primitive::kPrimChar:
2787 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002788 case Primitive::kPrimInt: {
2789 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002790 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002791 } else {
2792 DCHECK(value.IsConstant()) << value;
2793 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2794 __ b(slow_path->GetEntryLabel());
2795 }
2796 }
2797 break;
2798 }
2799 case Primitive::kPrimLong: {
2800 if (value.IsRegisterPair()) {
2801 __ orrs(IP,
2802 value.AsRegisterPairLow<Register>(),
2803 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2804 __ b(slow_path->GetEntryLabel(), EQ);
2805 } else {
2806 DCHECK(value.IsConstant()) << value;
2807 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2808 __ b(slow_path->GetEntryLabel());
2809 }
2810 }
2811 break;
2812 default:
2813 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2814 }
2815 }
Calin Juravled0d48522014-11-04 16:40:20 +00002816}
2817
Calin Juravle9aec02f2014-11-18 23:06:35 +00002818void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2819 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2820
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002821 LocationSummary* locations =
2822 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002823
2824 switch (op->GetResultType()) {
2825 case Primitive::kPrimInt: {
2826 locations->SetInAt(0, Location::RequiresRegister());
2827 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002828 // Make the output overlap, as it will be used to hold the masked
2829 // second input.
2830 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002831 break;
2832 }
2833 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002834 locations->SetInAt(0, Location::RequiresRegister());
2835 locations->SetInAt(1, Location::RequiresRegister());
2836 locations->AddTemp(Location::RequiresRegister());
2837 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002838 break;
2839 }
2840 default:
2841 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2842 }
2843}
2844
2845void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2846 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2847
2848 LocationSummary* locations = op->GetLocations();
2849 Location out = locations->Out();
2850 Location first = locations->InAt(0);
2851 Location second = locations->InAt(1);
2852
2853 Primitive::Type type = op->GetResultType();
2854 switch (type) {
2855 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002856 Register out_reg = out.AsRegister<Register>();
2857 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002858 // Arm doesn't mask the shift count so we need to do it ourselves.
2859 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002860 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002861 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002862 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002863 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002864 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002865 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002866 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002867 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002868 }
2869 } else {
2870 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2871 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2872 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2873 __ Mov(out_reg, first_reg);
2874 } else if (op->IsShl()) {
2875 __ Lsl(out_reg, first_reg, shift_value);
2876 } else if (op->IsShr()) {
2877 __ Asr(out_reg, first_reg, shift_value);
2878 } else {
2879 __ Lsr(out_reg, first_reg, shift_value);
2880 }
2881 }
2882 break;
2883 }
2884 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002885 Register o_h = out.AsRegisterPairHigh<Register>();
2886 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002887
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002888 Register temp = locations->GetTemp(0).AsRegister<Register>();
2889
2890 Register high = first.AsRegisterPairHigh<Register>();
2891 Register low = first.AsRegisterPairLow<Register>();
2892
2893 Register second_reg = second.AsRegister<Register>();
2894
Calin Juravle9aec02f2014-11-18 23:06:35 +00002895 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002896 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002897 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002898 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002899 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002900 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002901 __ Lsr(temp, low, temp);
2902 __ orr(o_h, o_h, ShifterOperand(temp));
2903 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002904 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002905 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002906 __ Lsl(o_h, low, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002907 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002908 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002909 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002910 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002911 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002912 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002913 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002914 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002915 __ Lsl(temp, high, temp);
2916 __ orr(o_l, o_l, ShifterOperand(temp));
2917 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002918 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002919 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002920 __ Asr(o_l, high, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002921 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002922 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002923 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002924 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002925 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002926 __ Lsr(o_l, low, o_h);
2927 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002928 __ Lsl(temp, high, temp);
2929 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002930 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002931 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002932 __ Lsr(o_l, high, temp, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002933 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002934 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002935 break;
2936 }
2937 default:
2938 LOG(FATAL) << "Unexpected operation type " << type;
2939 }
2940}
2941
2942void LocationsBuilderARM::VisitShl(HShl* shl) {
2943 HandleShift(shl);
2944}
2945
2946void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2947 HandleShift(shl);
2948}
2949
2950void LocationsBuilderARM::VisitShr(HShr* shr) {
2951 HandleShift(shr);
2952}
2953
2954void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2955 HandleShift(shr);
2956}
2957
2958void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2959 HandleShift(ushr);
2960}
2961
2962void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2963 HandleShift(ushr);
2964}
2965
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002966void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002967 LocationSummary* locations =
2968 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002969 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002970 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01002971 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002972 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002973}
2974
2975void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2976 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002977 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01002978 // Note: if heap poisoning is enabled, the entry point takes cares
2979 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002980 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2981 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002982 instruction->GetDexPc(),
2983 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002984}
2985
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002986void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2987 LocationSummary* locations =
2988 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2989 InvokeRuntimeCallingConvention calling_convention;
2990 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002991 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002992 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01002993 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002994}
2995
2996void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2997 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002998 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01002999 // Note: if heap poisoning is enabled, the entry point takes cares
3000 // of poisoning the reference.
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003001 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
3002 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003003 instruction->GetDexPc(),
3004 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003005}
3006
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003007void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003008 LocationSummary* locations =
3009 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003010 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3011 if (location.IsStackSlot()) {
3012 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3013 } else if (location.IsDoubleStackSlot()) {
3014 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003015 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003016 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003017}
3018
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003019void InstructionCodeGeneratorARM::VisitParameterValue(
3020 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003021 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003022}
3023
3024void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3025 LocationSummary* locations =
3026 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3027 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3028}
3029
3030void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3031 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003032}
3033
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003034void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003035 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003036 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003037 locations->SetInAt(0, Location::RequiresRegister());
3038 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003039}
3040
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003041void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3042 LocationSummary* locations = not_->GetLocations();
3043 Location out = locations->Out();
3044 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003045 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003046 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003047 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003048 break;
3049
3050 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003051 __ mvn(out.AsRegisterPairLow<Register>(),
3052 ShifterOperand(in.AsRegisterPairLow<Register>()));
3053 __ mvn(out.AsRegisterPairHigh<Register>(),
3054 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003055 break;
3056
3057 default:
3058 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3059 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003060}
3061
David Brazdil66d126e2015-04-03 16:02:44 +01003062void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3063 LocationSummary* locations =
3064 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3065 locations->SetInAt(0, Location::RequiresRegister());
3066 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3067}
3068
3069void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003070 LocationSummary* locations = bool_not->GetLocations();
3071 Location out = locations->Out();
3072 Location in = locations->InAt(0);
3073 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3074}
3075
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003076void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003077 LocationSummary* locations =
3078 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003079 switch (compare->InputAt(0)->GetType()) {
3080 case Primitive::kPrimLong: {
3081 locations->SetInAt(0, Location::RequiresRegister());
3082 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003083 // Output overlaps because it is written before doing the low comparison.
3084 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003085 break;
3086 }
3087 case Primitive::kPrimFloat:
3088 case Primitive::kPrimDouble: {
3089 locations->SetInAt(0, Location::RequiresFpuRegister());
3090 locations->SetInAt(1, Location::RequiresFpuRegister());
3091 locations->SetOut(Location::RequiresRegister());
3092 break;
3093 }
3094 default:
3095 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3096 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003097}
3098
3099void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003100 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003101 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003102 Location left = locations->InAt(0);
3103 Location right = locations->InAt(1);
3104
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003105 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003106 Primitive::Type type = compare->InputAt(0)->GetType();
3107 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003108 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003109 __ cmp(left.AsRegisterPairHigh<Register>(),
3110 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003111 __ b(&less, LT);
3112 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003113 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003114 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003115 __ cmp(left.AsRegisterPairLow<Register>(),
3116 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003117 break;
3118 }
3119 case Primitive::kPrimFloat:
3120 case Primitive::kPrimDouble: {
3121 __ LoadImmediate(out, 0);
3122 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003123 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003124 } else {
3125 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3126 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3127 }
3128 __ vmstat(); // transfer FP status register to ARM APSR.
3129 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003130 break;
3131 }
3132 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003133 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003134 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003135 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003136 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003137
3138 __ Bind(&greater);
3139 __ LoadImmediate(out, 1);
3140 __ b(&done);
3141
3142 __ Bind(&less);
3143 __ LoadImmediate(out, -1);
3144
3145 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003146}
3147
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003148void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003149 LocationSummary* locations =
3150 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003151 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3152 locations->SetInAt(i, Location::Any());
3153 }
3154 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003155}
3156
3157void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003158 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003159 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003160}
3161
Calin Juravle52c48962014-12-16 17:02:57 +00003162void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3163 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003164 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003165 switch (kind) {
3166 case MemBarrierKind::kAnyStore:
3167 case MemBarrierKind::kLoadAny:
3168 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003169 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003170 break;
3171 }
3172 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003173 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003174 break;
3175 }
3176 default:
3177 LOG(FATAL) << "Unexpected memory barrier " << kind;
3178 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003179 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003180}
3181
3182void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3183 uint32_t offset,
3184 Register out_lo,
3185 Register out_hi) {
3186 if (offset != 0) {
3187 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003188 __ add(IP, addr, ShifterOperand(out_lo));
3189 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003190 }
3191 __ ldrexd(out_lo, out_hi, addr);
3192}
3193
3194void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3195 uint32_t offset,
3196 Register value_lo,
3197 Register value_hi,
3198 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003199 Register temp2,
3200 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003201 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003202 if (offset != 0) {
3203 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003204 __ add(IP, addr, ShifterOperand(temp1));
3205 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003206 }
3207 __ Bind(&fail);
3208 // We need a load followed by store. (The address used in a STREX instruction must
3209 // be the same as the address in the most recently executed LDREX instruction.)
3210 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003211 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003212 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003213 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003214}
3215
3216void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3217 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3218
Nicolas Geoffray39468442014-09-02 15:17:15 +01003219 LocationSummary* locations =
3220 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003221 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003222
Calin Juravle52c48962014-12-16 17:02:57 +00003223 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003224 if (Primitive::IsFloatingPointType(field_type)) {
3225 locations->SetInAt(1, Location::RequiresFpuRegister());
3226 } else {
3227 locations->SetInAt(1, Location::RequiresRegister());
3228 }
3229
Calin Juravle52c48962014-12-16 17:02:57 +00003230 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003231 bool generate_volatile = field_info.IsVolatile()
3232 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003233 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003234 bool needs_write_barrier =
3235 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003236 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003237 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003238 if (needs_write_barrier) {
3239 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003240 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003241 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003242 // Arm encoding have some additional constraints for ldrexd/strexd:
3243 // - registers need to be consecutive
3244 // - the first register should be even but not R14.
3245 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3246 // enable Arm encoding.
3247 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3248
3249 locations->AddTemp(Location::RequiresRegister());
3250 locations->AddTemp(Location::RequiresRegister());
3251 if (field_type == Primitive::kPrimDouble) {
3252 // For doubles we need two more registers to copy the value.
3253 locations->AddTemp(Location::RegisterLocation(R2));
3254 locations->AddTemp(Location::RegisterLocation(R3));
3255 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003256 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003257}
3258
Calin Juravle52c48962014-12-16 17:02:57 +00003259void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003260 const FieldInfo& field_info,
3261 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003262 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3263
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003264 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003265 Register base = locations->InAt(0).AsRegister<Register>();
3266 Location value = locations->InAt(1);
3267
3268 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003269 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003270 Primitive::Type field_type = field_info.GetFieldType();
3271 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003272 bool needs_write_barrier =
3273 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003274
3275 if (is_volatile) {
3276 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3277 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003278
3279 switch (field_type) {
3280 case Primitive::kPrimBoolean:
3281 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003282 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003283 break;
3284 }
3285
3286 case Primitive::kPrimShort:
3287 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003288 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003289 break;
3290 }
3291
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003292 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003293 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003294 if (kPoisonHeapReferences && needs_write_barrier) {
3295 // Note that in the case where `value` is a null reference,
3296 // we do not enter this block, as a null reference does not
3297 // need poisoning.
3298 DCHECK_EQ(field_type, Primitive::kPrimNot);
3299 Register temp = locations->GetTemp(0).AsRegister<Register>();
3300 __ Mov(temp, value.AsRegister<Register>());
3301 __ PoisonHeapReference(temp);
3302 __ StoreToOffset(kStoreWord, temp, base, offset);
3303 } else {
3304 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3305 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003306 break;
3307 }
3308
3309 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003310 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003311 GenerateWideAtomicStore(base, offset,
3312 value.AsRegisterPairLow<Register>(),
3313 value.AsRegisterPairHigh<Register>(),
3314 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003315 locations->GetTemp(1).AsRegister<Register>(),
3316 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003317 } else {
3318 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003319 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003320 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003321 break;
3322 }
3323
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003324 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003325 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003326 break;
3327 }
3328
3329 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003330 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003331 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003332 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3333 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3334
3335 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3336
3337 GenerateWideAtomicStore(base, offset,
3338 value_reg_lo,
3339 value_reg_hi,
3340 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003341 locations->GetTemp(3).AsRegister<Register>(),
3342 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003343 } else {
3344 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003345 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003346 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003347 break;
3348 }
3349
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003350 case Primitive::kPrimVoid:
3351 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003352 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003353 }
Calin Juravle52c48962014-12-16 17:02:57 +00003354
Calin Juravle77520bc2015-01-12 18:45:46 +00003355 // Longs and doubles are handled in the switch.
3356 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3357 codegen_->MaybeRecordImplicitNullCheck(instruction);
3358 }
3359
3360 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3361 Register temp = locations->GetTemp(0).AsRegister<Register>();
3362 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003363 codegen_->MarkGCCard(
3364 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003365 }
3366
Calin Juravle52c48962014-12-16 17:02:57 +00003367 if (is_volatile) {
3368 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3369 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003370}
3371
Calin Juravle52c48962014-12-16 17:02:57 +00003372void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3373 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003374 LocationSummary* locations =
3375 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003376 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003377
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003378 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003379 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003380 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003381 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003382
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003383 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3384 locations->SetOut(Location::RequiresFpuRegister());
3385 } else {
3386 locations->SetOut(Location::RequiresRegister(),
3387 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3388 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003389 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003390 // Arm encoding have some additional constraints for ldrexd/strexd:
3391 // - registers need to be consecutive
3392 // - the first register should be even but not R14.
3393 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3394 // enable Arm encoding.
3395 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3396 locations->AddTemp(Location::RequiresRegister());
3397 locations->AddTemp(Location::RequiresRegister());
3398 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003399}
3400
Calin Juravle52c48962014-12-16 17:02:57 +00003401void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3402 const FieldInfo& field_info) {
3403 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003404
Calin Juravle52c48962014-12-16 17:02:57 +00003405 LocationSummary* locations = instruction->GetLocations();
3406 Register base = locations->InAt(0).AsRegister<Register>();
3407 Location out = locations->Out();
3408 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003409 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003410 Primitive::Type field_type = field_info.GetFieldType();
3411 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3412
3413 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003414 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003415 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003416 break;
3417 }
3418
3419 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003420 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003421 break;
3422 }
3423
3424 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003425 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003426 break;
3427 }
3428
3429 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003430 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003431 break;
3432 }
3433
3434 case Primitive::kPrimInt:
3435 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003436 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003437 break;
3438 }
3439
3440 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003441 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003442 GenerateWideAtomicLoad(base, offset,
3443 out.AsRegisterPairLow<Register>(),
3444 out.AsRegisterPairHigh<Register>());
3445 } else {
3446 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3447 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003448 break;
3449 }
3450
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003451 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003452 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003453 break;
3454 }
3455
3456 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003457 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003458 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003459 Register lo = locations->GetTemp(0).AsRegister<Register>();
3460 Register hi = locations->GetTemp(1).AsRegister<Register>();
3461 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003462 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003463 __ vmovdrr(out_reg, lo, hi);
3464 } else {
3465 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003466 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003467 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003468 break;
3469 }
3470
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003471 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003472 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003473 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003474 }
Calin Juravle52c48962014-12-16 17:02:57 +00003475
Calin Juravle77520bc2015-01-12 18:45:46 +00003476 // Doubles are handled in the switch.
3477 if (field_type != Primitive::kPrimDouble) {
3478 codegen_->MaybeRecordImplicitNullCheck(instruction);
3479 }
3480
Calin Juravle52c48962014-12-16 17:02:57 +00003481 if (is_volatile) {
3482 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3483 }
Roland Levillain4d027112015-07-01 15:41:14 +01003484
3485 if (field_type == Primitive::kPrimNot) {
3486 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3487 }
Calin Juravle52c48962014-12-16 17:02:57 +00003488}
3489
3490void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3491 HandleFieldSet(instruction, instruction->GetFieldInfo());
3492}
3493
3494void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003495 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003496}
3497
3498void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3499 HandleFieldGet(instruction, instruction->GetFieldInfo());
3500}
3501
3502void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3503 HandleFieldGet(instruction, instruction->GetFieldInfo());
3504}
3505
3506void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3507 HandleFieldGet(instruction, instruction->GetFieldInfo());
3508}
3509
3510void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3511 HandleFieldGet(instruction, instruction->GetFieldInfo());
3512}
3513
3514void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3515 HandleFieldSet(instruction, instruction->GetFieldInfo());
3516}
3517
3518void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003519 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003520}
3521
3522void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003523 LocationSummary* locations =
3524 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003525 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003526 if (instruction->HasUses()) {
3527 locations->SetOut(Location::SameAsFirstInput());
3528 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003529}
3530
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003531void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003532 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3533 return;
3534 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003535 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003536
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003537 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3538 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3539}
3540
3541void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003542 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003543 codegen_->AddSlowPath(slow_path);
3544
3545 LocationSummary* locations = instruction->GetLocations();
3546 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003547
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003548 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003549}
3550
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003551void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3552 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3553 GenerateImplicitNullCheck(instruction);
3554 } else {
3555 GenerateExplicitNullCheck(instruction);
3556 }
3557}
3558
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003559void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003560 LocationSummary* locations =
3561 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003562 locations->SetInAt(0, Location::RequiresRegister());
3563 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003564 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3565 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3566 } else {
3567 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3568 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003569}
3570
3571void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3572 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003573 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003574 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003575 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003576
Roland Levillain4d027112015-07-01 15:41:14 +01003577 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003578 case Primitive::kPrimBoolean: {
3579 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003580 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003581 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003582 size_t offset =
3583 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003584 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3585 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003586 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003587 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3588 }
3589 break;
3590 }
3591
3592 case Primitive::kPrimByte: {
3593 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003594 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003595 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003596 size_t offset =
3597 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003598 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3599 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003600 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003601 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3602 }
3603 break;
3604 }
3605
3606 case Primitive::kPrimShort: {
3607 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003608 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003609 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003610 size_t offset =
3611 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003612 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3613 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003614 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003615 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3616 }
3617 break;
3618 }
3619
3620 case Primitive::kPrimChar: {
3621 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003622 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003623 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003624 size_t offset =
3625 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003626 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3627 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003628 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003629 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3630 }
3631 break;
3632 }
3633
3634 case Primitive::kPrimInt:
3635 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003636 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3637 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003638 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003639 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003640 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003641 size_t offset =
3642 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003643 __ LoadFromOffset(kLoadWord, out, obj, offset);
3644 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003645 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003646 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3647 }
3648 break;
3649 }
3650
3651 case Primitive::kPrimLong: {
3652 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003653 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003654 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003655 size_t offset =
3656 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003657 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003658 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003659 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003660 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003661 }
3662 break;
3663 }
3664
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003665 case Primitive::kPrimFloat: {
3666 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3667 Location out = locations->Out();
3668 DCHECK(out.IsFpuRegister());
3669 if (index.IsConstant()) {
3670 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3671 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3672 } else {
3673 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3674 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3675 }
3676 break;
3677 }
3678
3679 case Primitive::kPrimDouble: {
3680 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3681 Location out = locations->Out();
3682 DCHECK(out.IsFpuRegisterPair());
3683 if (index.IsConstant()) {
3684 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3685 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3686 } else {
3687 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3688 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3689 }
3690 break;
3691 }
3692
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003693 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003694 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003695 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003696 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003697 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003698
3699 if (type == Primitive::kPrimNot) {
3700 Register out = locations->Out().AsRegister<Register>();
3701 __ MaybeUnpoisonHeapReference(out);
3702 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003703}
3704
3705void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003706 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003707
3708 bool needs_write_barrier =
3709 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3710 bool needs_runtime_call = instruction->NeedsTypeCheck();
3711
Nicolas Geoffray39468442014-09-02 15:17:15 +01003712 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003713 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3714 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003715 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003716 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3717 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3718 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003719 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003720 locations->SetInAt(0, Location::RequiresRegister());
3721 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003722 if (Primitive::IsFloatingPointType(value_type)) {
3723 locations->SetInAt(2, Location::RequiresFpuRegister());
3724 } else {
3725 locations->SetInAt(2, Location::RequiresRegister());
3726 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003727
3728 if (needs_write_barrier) {
3729 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003730 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003731 locations->AddTemp(Location::RequiresRegister());
3732 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003733 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003734}
3735
3736void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3737 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003738 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003739 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003740 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003741 bool needs_runtime_call = locations->WillCall();
3742 bool needs_write_barrier =
3743 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003744
3745 switch (value_type) {
3746 case Primitive::kPrimBoolean:
3747 case Primitive::kPrimByte: {
3748 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003749 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003750 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003751 size_t offset =
3752 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003753 __ StoreToOffset(kStoreByte, value, obj, offset);
3754 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003755 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003756 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3757 }
3758 break;
3759 }
3760
3761 case Primitive::kPrimShort:
3762 case Primitive::kPrimChar: {
3763 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003764 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003765 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003766 size_t offset =
3767 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003768 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3769 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003770 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003771 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3772 }
3773 break;
3774 }
3775
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003776 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003777 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003778 if (!needs_runtime_call) {
3779 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003780 Register value = locations->InAt(2).AsRegister<Register>();
Roland Levillain4d027112015-07-01 15:41:14 +01003781 Register source = value;
3782 if (kPoisonHeapReferences && needs_write_barrier) {
3783 // Note that in the case where `value` is a null reference,
3784 // we do not enter this block, as a null reference does not
3785 // need poisoning.
3786 DCHECK_EQ(value_type, Primitive::kPrimNot);
3787 Register temp = locations->GetTemp(0).AsRegister<Register>();
3788 __ Mov(temp, value);
3789 __ PoisonHeapReference(temp);
3790 source = temp;
3791 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003792 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003793 size_t offset =
3794 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain4d027112015-07-01 15:41:14 +01003795 __ StoreToOffset(kStoreWord, source, obj, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003796 } else {
3797 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003798 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003799 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003800 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003801 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003802 if (needs_write_barrier) {
3803 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003804 Register temp = locations->GetTemp(0).AsRegister<Register>();
3805 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003806 codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003807 }
3808 } else {
3809 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003810 // Note: if heap poisoning is enabled, pAputObject takes cares
3811 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003812 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3813 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003814 instruction->GetDexPc(),
3815 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003816 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003817 break;
3818 }
3819
3820 case Primitive::kPrimLong: {
3821 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003822 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003823 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003824 size_t offset =
3825 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003826 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003827 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003828 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003829 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003830 }
3831 break;
3832 }
3833
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003834 case Primitive::kPrimFloat: {
3835 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3836 Location value = locations->InAt(2);
3837 DCHECK(value.IsFpuRegister());
3838 if (index.IsConstant()) {
3839 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3840 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3841 } else {
3842 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3843 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3844 }
3845 break;
3846 }
3847
3848 case Primitive::kPrimDouble: {
3849 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3850 Location value = locations->InAt(2);
3851 DCHECK(value.IsFpuRegisterPair());
3852 if (index.IsConstant()) {
3853 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3854 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3855 } else {
3856 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3857 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3858 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003859
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003860 break;
3861 }
3862
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003863 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003864 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003865 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003867
3868 // Ints and objects are handled in the switch.
3869 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3870 codegen_->MaybeRecordImplicitNullCheck(instruction);
3871 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003872}
3873
3874void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003875 LocationSummary* locations =
3876 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003877 locations->SetInAt(0, Location::RequiresRegister());
3878 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003879}
3880
3881void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3882 LocationSummary* locations = instruction->GetLocations();
3883 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003884 Register obj = locations->InAt(0).AsRegister<Register>();
3885 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003886 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003887 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003888}
3889
3890void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003891 LocationSummary* locations =
3892 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003893 locations->SetInAt(0, Location::RequiresRegister());
3894 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003895 if (instruction->HasUses()) {
3896 locations->SetOut(Location::SameAsFirstInput());
3897 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003898}
3899
3900void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3901 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003902 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003903 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003904 codegen_->AddSlowPath(slow_path);
3905
Roland Levillain271ab9c2014-11-27 15:23:57 +00003906 Register index = locations->InAt(0).AsRegister<Register>();
3907 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003908
3909 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01003910 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003911}
3912
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003913void CodeGeneratorARM::MarkGCCard(Register temp,
3914 Register card,
3915 Register object,
3916 Register value,
3917 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003918 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003919 if (can_be_null) {
3920 __ CompareAndBranchIfZero(value, &is_null);
3921 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003922 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3923 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3924 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003925 if (can_be_null) {
3926 __ Bind(&is_null);
3927 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003928}
3929
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003930void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3931 temp->SetLocations(nullptr);
3932}
3933
3934void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3935 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003936 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003937}
3938
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003939void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003940 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003941 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003942}
3943
3944void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003945 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3946}
3947
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003948void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3949 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3950}
3951
3952void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003953 HBasicBlock* block = instruction->GetBlock();
3954 if (block->GetLoopInformation() != nullptr) {
3955 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3956 // The back edge will generate the suspend check.
3957 return;
3958 }
3959 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3960 // The goto will generate the suspend check.
3961 return;
3962 }
3963 GenerateSuspendCheck(instruction, nullptr);
3964}
3965
3966void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3967 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003968 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003969 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
3970 if (slow_path == nullptr) {
3971 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
3972 instruction->SetSlowPath(slow_path);
3973 codegen_->AddSlowPath(slow_path);
3974 if (successor != nullptr) {
3975 DCHECK(successor->IsLoopHeader());
3976 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3977 }
3978 } else {
3979 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3980 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003981
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003982 __ LoadFromOffset(
3983 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003984 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003985 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003986 __ Bind(slow_path->GetReturnLabel());
3987 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003988 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003989 __ b(slow_path->GetEntryLabel());
3990 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003991}
3992
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003993ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3994 return codegen_->GetAssembler();
3995}
3996
3997void ParallelMoveResolverARM::EmitMove(size_t index) {
3998 MoveOperands* move = moves_.Get(index);
3999 Location source = move->GetSource();
4000 Location destination = move->GetDestination();
4001
4002 if (source.IsRegister()) {
4003 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004004 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004005 } else {
4006 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004007 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004008 SP, destination.GetStackIndex());
4009 }
4010 } else if (source.IsStackSlot()) {
4011 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004012 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004013 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004014 } else if (destination.IsFpuRegister()) {
4015 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004016 } else {
4017 DCHECK(destination.IsStackSlot());
4018 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4019 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4020 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004021 } else if (source.IsFpuRegister()) {
4022 if (destination.IsFpuRegister()) {
4023 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004024 } else {
4025 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004026 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4027 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004028 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004029 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004030 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4031 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004032 } else if (destination.IsRegisterPair()) {
4033 DCHECK(ExpectedPairLayout(destination));
4034 __ LoadFromOffset(
4035 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4036 } else {
4037 DCHECK(destination.IsFpuRegisterPair()) << destination;
4038 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4039 SP,
4040 source.GetStackIndex());
4041 }
4042 } else if (source.IsRegisterPair()) {
4043 if (destination.IsRegisterPair()) {
4044 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4045 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4046 } else {
4047 DCHECK(destination.IsDoubleStackSlot()) << destination;
4048 DCHECK(ExpectedPairLayout(source));
4049 __ StoreToOffset(
4050 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4051 }
4052 } else if (source.IsFpuRegisterPair()) {
4053 if (destination.IsFpuRegisterPair()) {
4054 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4055 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4056 } else {
4057 DCHECK(destination.IsDoubleStackSlot()) << destination;
4058 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4059 SP,
4060 destination.GetStackIndex());
4061 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004062 } else {
4063 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004064 HConstant* constant = source.GetConstant();
4065 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4066 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004067 if (destination.IsRegister()) {
4068 __ LoadImmediate(destination.AsRegister<Register>(), value);
4069 } else {
4070 DCHECK(destination.IsStackSlot());
4071 __ LoadImmediate(IP, value);
4072 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4073 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004074 } else if (constant->IsLongConstant()) {
4075 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004076 if (destination.IsRegisterPair()) {
4077 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4078 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004079 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004080 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004081 __ LoadImmediate(IP, Low32Bits(value));
4082 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4083 __ LoadImmediate(IP, High32Bits(value));
4084 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4085 }
4086 } else if (constant->IsDoubleConstant()) {
4087 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004088 if (destination.IsFpuRegisterPair()) {
4089 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004090 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004091 DCHECK(destination.IsDoubleStackSlot()) << destination;
4092 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004093 __ LoadImmediate(IP, Low32Bits(int_value));
4094 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4095 __ LoadImmediate(IP, High32Bits(int_value));
4096 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4097 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004098 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004099 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004100 float value = constant->AsFloatConstant()->GetValue();
4101 if (destination.IsFpuRegister()) {
4102 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4103 } else {
4104 DCHECK(destination.IsStackSlot());
4105 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4106 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4107 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004108 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004109 }
4110}
4111
4112void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4113 __ Mov(IP, reg);
4114 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4115 __ StoreToOffset(kStoreWord, IP, SP, mem);
4116}
4117
4118void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4119 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4120 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4121 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4122 SP, mem1 + stack_offset);
4123 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4124 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4125 SP, mem2 + stack_offset);
4126 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4127}
4128
4129void ParallelMoveResolverARM::EmitSwap(size_t index) {
4130 MoveOperands* move = moves_.Get(index);
4131 Location source = move->GetSource();
4132 Location destination = move->GetDestination();
4133
4134 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004135 DCHECK_NE(source.AsRegister<Register>(), IP);
4136 DCHECK_NE(destination.AsRegister<Register>(), IP);
4137 __ Mov(IP, source.AsRegister<Register>());
4138 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4139 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004140 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004141 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004142 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004143 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004144 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4145 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004146 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004147 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004148 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004149 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004150 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004151 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004152 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004153 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004154 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4155 destination.AsRegisterPairHigh<Register>(),
4156 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004157 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004158 Register low_reg = source.IsRegisterPair()
4159 ? source.AsRegisterPairLow<Register>()
4160 : destination.AsRegisterPairLow<Register>();
4161 int mem = source.IsRegisterPair()
4162 ? destination.GetStackIndex()
4163 : source.GetStackIndex();
4164 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004165 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004166 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004167 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004168 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004169 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4170 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004171 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004172 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004173 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004174 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4175 DRegister reg = source.IsFpuRegisterPair()
4176 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4177 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4178 int mem = source.IsFpuRegisterPair()
4179 ? destination.GetStackIndex()
4180 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004181 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004182 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004183 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004184 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4185 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4186 : destination.AsFpuRegister<SRegister>();
4187 int mem = source.IsFpuRegister()
4188 ? destination.GetStackIndex()
4189 : source.GetStackIndex();
4190
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004191 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004192 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004193 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004194 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004195 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4196 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004197 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004198 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004199 }
4200}
4201
4202void ParallelMoveResolverARM::SpillScratch(int reg) {
4203 __ Push(static_cast<Register>(reg));
4204}
4205
4206void ParallelMoveResolverARM::RestoreScratch(int reg) {
4207 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004208}
4209
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004210void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004211 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4212 ? LocationSummary::kCallOnSlowPath
4213 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004214 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004215 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004216 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004217 locations->SetOut(Location::RequiresRegister());
4218}
4219
4220void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004221 LocationSummary* locations = cls->GetLocations();
4222 Register out = locations->Out().AsRegister<Register>();
4223 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004224 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004225 DCHECK(!cls->CanCallRuntime());
4226 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004227 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004228 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004229 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004230 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004231 __ LoadFromOffset(kLoadWord,
4232 out,
4233 current_method,
Mathieu Chartiere401d142015-04-22 13:56:20 -07004234 ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004235 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01004236 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004237
4238 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
4239 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4240 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004241 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004242 if (cls->MustGenerateClinitCheck()) {
4243 GenerateClassInitializationCheck(slow_path, out);
4244 } else {
4245 __ Bind(slow_path->GetExitLabel());
4246 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004247 }
4248}
4249
4250void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4251 LocationSummary* locations =
4252 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4253 locations->SetInAt(0, Location::RequiresRegister());
4254 if (check->HasUses()) {
4255 locations->SetOut(Location::SameAsFirstInput());
4256 }
4257}
4258
4259void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004260 // We assume the class is not null.
4261 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
4262 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004263 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004264 GenerateClassInitializationCheck(slow_path,
4265 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004266}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004267
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004268void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
4269 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004270 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4271 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4272 __ b(slow_path->GetEntryLabel(), LT);
4273 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4274 // properly. Therefore, we do a memory fence.
4275 __ dmb(ISH);
4276 __ Bind(slow_path->GetExitLabel());
4277}
4278
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004279void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4280 LocationSummary* locations =
4281 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004282 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004283 locations->SetOut(Location::RequiresRegister());
4284}
4285
4286void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
4287 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
4288 codegen_->AddSlowPath(slow_path);
4289
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004290 LocationSummary* locations = load->GetLocations();
4291 Register out = locations->Out().AsRegister<Register>();
4292 Register current_method = locations->InAt(0).AsRegister<Register>();
4293 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004294 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004295 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Roland Levillain4d027112015-07-01 15:41:14 +01004296 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004297 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01004298 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004299 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004300 __ Bind(slow_path->GetExitLabel());
4301}
4302
David Brazdilcb1c0552015-08-04 16:22:25 +01004303static int32_t GetExceptionTlsOffset() {
4304 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4305}
4306
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004307void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4308 LocationSummary* locations =
4309 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4310 locations->SetOut(Location::RequiresRegister());
4311}
4312
4313void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004314 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004315 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4316}
4317
4318void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4319 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4320}
4321
4322void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004323 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004324 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004325}
4326
4327void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4328 LocationSummary* locations =
4329 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4330 InvokeRuntimeCallingConvention calling_convention;
4331 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4332}
4333
4334void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4335 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004336 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004337}
4338
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004339void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004340 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4341 ? LocationSummary::kNoCall
4342 : LocationSummary::kCallOnSlowPath;
4343 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4344 locations->SetInAt(0, Location::RequiresRegister());
4345 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004346 // The out register is used as a temporary, so it overlaps with the inputs.
4347 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004348}
4349
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004350void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004351 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004352 Register obj = locations->InAt(0).AsRegister<Register>();
4353 Register cls = locations->InAt(1).AsRegister<Register>();
4354 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004355 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004356 Label done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004357 SlowPathCodeARM* slow_path = nullptr;
4358
4359 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004360 // avoid null check if we know obj is not null.
4361 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004362 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004363 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004364 // Compare the class of `obj` with `cls`.
4365 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004366 __ MaybeUnpoisonHeapReference(out);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004367 __ cmp(out, ShifterOperand(cls));
4368 if (instruction->IsClassFinal()) {
4369 // Classes must be equal for the instanceof to succeed.
4370 __ b(&zero, NE);
4371 __ LoadImmediate(out, 1);
4372 __ b(&done);
4373 } else {
4374 // If the classes are not equal, we go into a slow path.
4375 DCHECK(locations->OnlyCallsOnSlowPath());
4376 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004377 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004378 codegen_->AddSlowPath(slow_path);
4379 __ b(slow_path->GetEntryLabel(), NE);
4380 __ LoadImmediate(out, 1);
4381 __ b(&done);
4382 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004383
4384 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4385 __ Bind(&zero);
4386 __ LoadImmediate(out, 0);
4387 }
4388
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004389 if (slow_path != nullptr) {
4390 __ Bind(slow_path->GetExitLabel());
4391 }
4392 __ Bind(&done);
4393}
4394
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004395void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
4396 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4397 instruction, LocationSummary::kCallOnSlowPath);
4398 locations->SetInAt(0, Location::RequiresRegister());
4399 locations->SetInAt(1, Location::RequiresRegister());
4400 locations->AddTemp(Location::RequiresRegister());
4401}
4402
4403void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4404 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 Register obj = locations->InAt(0).AsRegister<Register>();
4406 Register cls = locations->InAt(1).AsRegister<Register>();
4407 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004408 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4409
4410 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4411 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4412 codegen_->AddSlowPath(slow_path);
4413
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004414 // avoid null check if we know obj is not null.
4415 if (instruction->MustDoNullCheck()) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004416 __ CompareAndBranchIfZero(obj, slow_path->GetExitLabel());
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004417 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004418 // Compare the class of `obj` with `cls`.
4419 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004420 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004421 __ cmp(temp, ShifterOperand(cls));
Roland Levillain4d027112015-07-01 15:41:14 +01004422 // The checkcast succeeds if the classes are equal (fast path).
4423 // Otherwise, we need to go into the slow path to check the types.
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004424 __ b(slow_path->GetEntryLabel(), NE);
4425 __ Bind(slow_path->GetExitLabel());
4426}
4427
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004428void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4429 LocationSummary* locations =
4430 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4431 InvokeRuntimeCallingConvention calling_convention;
4432 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4433}
4434
4435void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4436 codegen_->InvokeRuntime(instruction->IsEnter()
4437 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4438 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004439 instruction->GetDexPc(),
4440 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004441}
4442
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004443void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4444void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4445void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4446
4447void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4448 LocationSummary* locations =
4449 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4450 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4451 || instruction->GetResultType() == Primitive::kPrimLong);
4452 locations->SetInAt(0, Location::RequiresRegister());
4453 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004454 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004455}
4456
4457void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4458 HandleBitwiseOperation(instruction);
4459}
4460
4461void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4462 HandleBitwiseOperation(instruction);
4463}
4464
4465void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4466 HandleBitwiseOperation(instruction);
4467}
4468
4469void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4470 LocationSummary* locations = instruction->GetLocations();
4471
4472 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004473 Register first = locations->InAt(0).AsRegister<Register>();
4474 Register second = locations->InAt(1).AsRegister<Register>();
4475 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004476 if (instruction->IsAnd()) {
4477 __ and_(out, first, ShifterOperand(second));
4478 } else if (instruction->IsOr()) {
4479 __ orr(out, first, ShifterOperand(second));
4480 } else {
4481 DCHECK(instruction->IsXor());
4482 __ eor(out, first, ShifterOperand(second));
4483 }
4484 } else {
4485 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4486 Location first = locations->InAt(0);
4487 Location second = locations->InAt(1);
4488 Location out = locations->Out();
4489 if (instruction->IsAnd()) {
4490 __ and_(out.AsRegisterPairLow<Register>(),
4491 first.AsRegisterPairLow<Register>(),
4492 ShifterOperand(second.AsRegisterPairLow<Register>()));
4493 __ and_(out.AsRegisterPairHigh<Register>(),
4494 first.AsRegisterPairHigh<Register>(),
4495 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4496 } else if (instruction->IsOr()) {
4497 __ orr(out.AsRegisterPairLow<Register>(),
4498 first.AsRegisterPairLow<Register>(),
4499 ShifterOperand(second.AsRegisterPairLow<Register>()));
4500 __ orr(out.AsRegisterPairHigh<Register>(),
4501 first.AsRegisterPairHigh<Register>(),
4502 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4503 } else {
4504 DCHECK(instruction->IsXor());
4505 __ eor(out.AsRegisterPairLow<Register>(),
4506 first.AsRegisterPairLow<Register>(),
4507 ShifterOperand(second.AsRegisterPairLow<Register>()));
4508 __ eor(out.AsRegisterPairHigh<Register>(),
4509 first.AsRegisterPairHigh<Register>(),
4510 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4511 }
4512 }
4513}
4514
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004515void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004516 // For better instruction scheduling we load the direct code pointer before the method pointer.
4517 bool direct_code_loaded = false;
4518 switch (invoke->GetCodePtrLocation()) {
4519 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4520 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4521 break;
4522 }
4523 // Calls across dex files are more likely to exceed the available BL range,
4524 // so use absolute patch by falling through to kDirectCodeFixup.
4525 FALLTHROUGH_INTENDED;
4526 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4527 // LR = code address from literal pool with link-time patch.
4528 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4529 direct_code_loaded = true;
4530 break;
4531 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4532 // LR = invoke->GetDirectCodePtr();
4533 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4534 direct_code_loaded = true;
4535 break;
4536 default:
4537 break;
4538 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004539
Vladimir Marko58155012015-08-19 12:49:41 +00004540 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4541 switch (invoke->GetMethodLoadKind()) {
4542 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
4543 // temp = thread->string_init_entrypoint
4544 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
4545 break;
4546 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4547 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4548 break;
4549 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4550 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4551 break;
4552 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4553 __ LoadLiteral(temp.AsRegister<Register>(),
4554 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4555 break;
4556 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
4557 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
4558 FALLTHROUGH_INTENDED;
4559 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4560 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4561 Register method_reg;
4562 Register reg = temp.AsRegister<Register>();
4563 if (current_method.IsRegister()) {
4564 method_reg = current_method.AsRegister<Register>();
4565 } else {
4566 DCHECK(invoke->GetLocations()->Intrinsified());
4567 DCHECK(!current_method.IsValid());
4568 method_reg = reg;
4569 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
4570 }
4571 // temp = current_method->dex_cache_resolved_methods_;
4572 __ LoadFromOffset(
4573 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
4574 // temp = temp[index_in_cache]
4575 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
4576 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
4577 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01004578 }
Vladimir Marko58155012015-08-19 12:49:41 +00004579 }
4580
4581 switch (invoke->GetCodePtrLocation()) {
4582 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
4583 __ bl(GetFrameEntryLabel());
4584 break;
4585 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4586 if (!direct_code_loaded) {
4587 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
4588 __ Bind(&relative_call_patches_.back().label);
4589 Label label;
4590 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
4591 __ Bind(&label);
4592 break;
4593 }
4594 // If we loaded the direct code above, fall through.
4595 FALLTHROUGH_INTENDED;
4596 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4597 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4598 // LR prepared above for better instruction scheduling.
4599 DCHECK(direct_code_loaded);
4600 // LR()
4601 __ blx(LR);
4602 break;
4603 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4604 // LR = callee_method->entry_point_from_quick_compiled_code_
4605 __ LoadFromOffset(
4606 kLoadWord, LR, callee_method.AsRegister<Register>(),
4607 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
4608 // LR()
4609 __ blx(LR);
4610 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004611 }
4612
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004613 DCHECK(!IsLeafMethod());
4614}
4615
Vladimir Marko58155012015-08-19 12:49:41 +00004616void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
4617 DCHECK(linker_patches->empty());
4618 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
4619 linker_patches->reserve(size);
4620 for (const auto& entry : method_patches_) {
4621 const MethodReference& target_method = entry.first;
4622 Literal* literal = entry.second;
4623 DCHECK(literal->GetLabel()->IsBound());
4624 uint32_t literal_offset = literal->GetLabel()->Position();
4625 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
4626 target_method.dex_file,
4627 target_method.dex_method_index));
4628 }
4629 for (const auto& entry : call_patches_) {
4630 const MethodReference& target_method = entry.first;
4631 Literal* literal = entry.second;
4632 DCHECK(literal->GetLabel()->IsBound());
4633 uint32_t literal_offset = literal->GetLabel()->Position();
4634 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
4635 target_method.dex_file,
4636 target_method.dex_method_index));
4637 }
4638 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
4639 uint32_t literal_offset = info.label.Position();
4640 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
4641 info.target_method.dex_file,
4642 info.target_method.dex_method_index));
4643 }
4644}
4645
4646Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
4647 MethodToLiteralMap* map) {
4648 // Look up the literal for target_method.
4649 auto lb = map->lower_bound(target_method);
4650 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
4651 return lb->second;
4652 }
4653 // We don't have a literal for this method yet, insert a new one.
4654 Literal* literal = __ NewLiteral<uint32_t>(0u);
4655 map->PutBefore(lb, target_method, literal);
4656 return literal;
4657}
4658
4659Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
4660 return DeduplicateMethodLiteral(target_method, &method_patches_);
4661}
4662
4663Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
4664 return DeduplicateMethodLiteral(target_method, &call_patches_);
4665}
4666
Calin Juravleb1498f62015-02-16 13:13:29 +00004667void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4668 // Nothing to do, this should be removed during prepare for register allocator.
4669 UNUSED(instruction);
4670 LOG(FATAL) << "Unreachable";
4671}
4672
4673void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4674 // Nothing to do, this should be removed during prepare for register allocator.
4675 UNUSED(instruction);
4676 LOG(FATAL) << "Unreachable";
4677}
4678
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004679void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
4680 DCHECK(codegen_->IsBaseline());
4681 LocationSummary* locations =
4682 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4683 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4684}
4685
4686void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4687 DCHECK(codegen_->IsBaseline());
4688 // Will be generated at use site.
4689}
4690
Roland Levillain4d027112015-07-01 15:41:14 +01004691#undef __
4692#undef QUICK_ENTRY_POINT
4693
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004694} // namespace arm
4695} // namespace art