blob: a98d9c68b7e78d979e0784ce94feadbbb51e69e6 [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
Roland Levillain3b359c72015-11-17 19:35:12 +000037template<class MirrorType>
38class GcRoot;
39
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040namespace arm {
41
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000042static bool ExpectedPairLayout(Location location) {
43 // We expected this for both core and fpu register pairs.
44 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
45}
46
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010047static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010048static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010049
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000050// We unconditionally allocate R5 to ensure we can do long operations
51// with baseline.
52static constexpr Register kCoreSavedRegisterForBaseline = R5;
53static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070054 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000055static constexpr SRegister kFpuCalleeSaves[] =
56 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010057
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000058// D31 cannot be split into two S registers, and the register allocator only works on
59// S registers. Therefore there is no need to block it.
60static constexpr DRegister DTMP = D31;
61
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070062static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6;
63
Roland Levillain62a46b22015-06-01 18:24:13 +010064#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010065#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066
Andreas Gampe85b62f22015-09-09 13:15:38 -070067class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070
Alexandre Rames67555f72014-11-18 10:55:16 +000071 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010072 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000074 if (instruction_->CanThrowIntoCatchBlock()) {
75 // Live registers will be restored in the catch block if caught.
76 SaveLiveRegisters(codegen, instruction_->GetLocations());
77 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010078 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000079 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000080 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 }
82
Alexandre Rames8158f282015-08-07 10:26:17 +010083 bool IsFatal() const OVERRIDE { return true; }
84
Alexandre Rames9931f312015-06-19 14:47:01 +010085 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
86
Nicolas Geoffraye5038322014-07-04 09:41:32 +010087 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010088 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010089 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
90};
91
Andreas Gampe85b62f22015-09-09 13:15:38 -070092class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000093 public:
94 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
95
Alexandre Rames67555f72014-11-18 10:55:16 +000096 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000097 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
98 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000099 if (instruction_->CanThrowIntoCatchBlock()) {
100 // Live registers will be restored in the catch block if caught.
101 SaveLiveRegisters(codegen, instruction_->GetLocations());
102 }
Calin Juravled0d48522014-11-04 16:40:20 +0000103 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000104 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000105 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000106 }
107
Alexandre Rames8158f282015-08-07 10:26:17 +0100108 bool IsFatal() const OVERRIDE { return true; }
109
Alexandre Rames9931f312015-06-19 14:47:01 +0100110 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
111
Calin Juravled0d48522014-11-04 16:40:20 +0000112 private:
113 HDivZeroCheck* const instruction_;
114 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
115};
116
Andreas Gampe85b62f22015-09-09 13:15:38 -0700117class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000119 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100120 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121
Alexandre Rames67555f72014-11-18 10:55:16 +0000122 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100123 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000124 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000125 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100126 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000127 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000128 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000129 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100130 if (successor_ == nullptr) {
131 __ b(GetReturnLabel());
132 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100133 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135 }
136
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100137 Label* GetReturnLabel() {
138 DCHECK(successor_ == nullptr);
139 return &return_label_;
140 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000141
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100142 HBasicBlock* GetSuccessor() const {
143 return successor_;
144 }
145
Alexandre Rames9931f312015-06-19 14:47:01 +0100146 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
147
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 private:
149 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100150 // If not null, the block to branch to after the suspend check.
151 HBasicBlock* const successor_;
152
153 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154 Label return_label_;
155
156 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
157};
158
Andreas Gampe85b62f22015-09-09 13:15:38 -0700159class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100161 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
162 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100163
Alexandre Rames67555f72014-11-18 10:55:16 +0000164 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100165 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100166 LocationSummary* locations = instruction_->GetLocations();
167
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100168 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000169 if (instruction_->CanThrowIntoCatchBlock()) {
170 // Live registers will be restored in the catch block if caught.
171 SaveLiveRegisters(codegen, instruction_->GetLocations());
172 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000173 // We're moving two locations to locations that could overlap, so we need a parallel
174 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100175 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000176 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100177 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000178 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100179 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100180 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100181 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
182 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100183 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000184 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000185 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100186 }
187
Alexandre Rames8158f282015-08-07 10:26:17 +0100188 bool IsFatal() const OVERRIDE { return true; }
189
Alexandre Rames9931f312015-06-19 14:47:01 +0100190 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
191
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100192 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100193 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100194
195 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
196};
197
Andreas Gampe85b62f22015-09-09 13:15:38 -0700198class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100199 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000200 LoadClassSlowPathARM(HLoadClass* cls,
201 HInstruction* at,
202 uint32_t dex_pc,
203 bool do_clinit)
204 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
205 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
206 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207
Alexandre Rames67555f72014-11-18 10:55:16 +0000208 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 LocationSummary* locations = at_->GetLocations();
210
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100211 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
212 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000213 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100214
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100215 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000216 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000217 int32_t entry_point_offset = do_clinit_
218 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
219 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000220 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000221 if (do_clinit_) {
222 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
223 } else {
224 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
225 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226
227 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000228 Location out = locations->Out();
229 if (out.IsValid()) {
230 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000231 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
232 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000233 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100234 __ b(GetExitLabel());
235 }
236
Alexandre Rames9931f312015-06-19 14:47:01 +0100237 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
238
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100239 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000240 // The class this slow path will load.
241 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100242
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000243 // The instruction where this slow path is happening.
244 // (Might be the load class or an initialization check).
245 HInstruction* const at_;
246
247 // The dex PC of `at_`.
248 const uint32_t dex_pc_;
249
250 // Whether to initialize the class.
251 const bool do_clinit_;
252
253 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100254};
255
Andreas Gampe85b62f22015-09-09 13:15:38 -0700256class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000257 public:
258 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
259
Alexandre Rames67555f72014-11-18 10:55:16 +0000260 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000261 LocationSummary* locations = instruction_->GetLocations();
262 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
263
264 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
265 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000266 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267
268 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800269 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000270 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000271 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000272 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000273 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
274
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000275 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000276 __ b(GetExitLabel());
277 }
278
Alexandre Rames9931f312015-06-19 14:47:01 +0100279 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
280
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000281 private:
282 HLoadString* const instruction_;
283
284 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
285};
286
Andreas Gampe85b62f22015-09-09 13:15:38 -0700287class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000288 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000289 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
290 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000291
Alexandre Rames67555f72014-11-18 10:55:16 +0000292 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000293 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100294 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
295 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000296 DCHECK(instruction_->IsCheckCast()
297 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000298
299 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
300 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000301
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000302 if (!is_fatal_) {
303 SaveLiveRegisters(codegen, locations);
304 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000305
306 // We're moving two locations to locations that could overlap, so we need a parallel
307 // move resolver.
308 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000309 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100310 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000311 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100312 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100313 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100314 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
315 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000316
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000317 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100318 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
319 instruction_,
320 instruction_->GetDexPc(),
321 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000322 CheckEntrypointTypes<
323 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000324 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
325 } else {
326 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100327 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
328 instruction_,
329 instruction_->GetDexPc(),
330 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000331 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000332 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000333
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000334 if (!is_fatal_) {
335 RestoreLiveRegisters(codegen, locations);
336 __ b(GetExitLabel());
337 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000338 }
339
Alexandre Rames9931f312015-06-19 14:47:01 +0100340 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
341
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000342 bool IsFatal() const OVERRIDE { return is_fatal_; }
343
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000344 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000345 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000346 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000347
348 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
349};
350
Andreas Gampe85b62f22015-09-09 13:15:38 -0700351class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700352 public:
353 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
354 : instruction_(instruction) {}
355
356 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
357 __ Bind(GetEntryLabel());
358 SaveLiveRegisters(codegen, instruction_->GetLocations());
359 DCHECK(instruction_->IsDeoptimize());
360 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
361 uint32_t dex_pc = deoptimize->GetDexPc();
362 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
363 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000364 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700365 }
366
Alexandre Rames9931f312015-06-19 14:47:01 +0100367 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
368
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700369 private:
370 HInstruction* const instruction_;
371 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
372};
373
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100374class ArraySetSlowPathARM : public SlowPathCode {
375 public:
376 explicit ArraySetSlowPathARM(HInstruction* instruction) : instruction_(instruction) {}
377
378 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
379 LocationSummary* locations = instruction_->GetLocations();
380 __ Bind(GetEntryLabel());
381 SaveLiveRegisters(codegen, locations);
382
383 InvokeRuntimeCallingConvention calling_convention;
384 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
385 parallel_move.AddMove(
386 locations->InAt(0),
387 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
388 Primitive::kPrimNot,
389 nullptr);
390 parallel_move.AddMove(
391 locations->InAt(1),
392 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
393 Primitive::kPrimInt,
394 nullptr);
395 parallel_move.AddMove(
396 locations->InAt(2),
397 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
398 Primitive::kPrimNot,
399 nullptr);
400 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
401
402 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
403 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
404 instruction_,
405 instruction_->GetDexPc(),
406 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000407 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100408 RestoreLiveRegisters(codegen, locations);
409 __ b(GetExitLabel());
410 }
411
412 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
413
414 private:
415 HInstruction* const instruction_;
416
417 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
418};
419
Roland Levillain3b359c72015-11-17 19:35:12 +0000420// Slow path generating a read barrier for a heap reference.
421class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
422 public:
423 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
424 Location out,
425 Location ref,
426 Location obj,
427 uint32_t offset,
428 Location index)
429 : instruction_(instruction),
430 out_(out),
431 ref_(ref),
432 obj_(obj),
433 offset_(offset),
434 index_(index) {
435 DCHECK(kEmitCompilerReadBarrier);
436 // If `obj` is equal to `out` or `ref`, it means the initial object
437 // has been overwritten by (or after) the heap object reference load
438 // to be instrumented, e.g.:
439 //
440 // __ LoadFromOffset(kLoadWord, out, out, offset);
441 // codegen_->GenerateReadBarrier(instruction, out_loc, out_loc, out_loc, offset);
442 //
443 // In that case, we have lost the information about the original
444 // object, and the emitted read barrier cannot work properly.
445 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
446 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
447 }
448
449 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
450 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
451 LocationSummary* locations = instruction_->GetLocations();
452 Register reg_out = out_.AsRegister<Register>();
453 DCHECK(locations->CanCall());
454 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
455 DCHECK(!instruction_->IsInvoke() ||
456 (instruction_->IsInvokeStaticOrDirect() &&
457 instruction_->GetLocations()->Intrinsified()));
458
459 __ Bind(GetEntryLabel());
460 SaveLiveRegisters(codegen, locations);
461
462 // We may have to change the index's value, but as `index_` is a
463 // constant member (like other "inputs" of this slow path),
464 // introduce a copy of it, `index`.
465 Location index = index_;
466 if (index_.IsValid()) {
467 // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
468 if (instruction_->IsArrayGet()) {
469 // Compute the actual memory offset and store it in `index`.
470 Register index_reg = index_.AsRegister<Register>();
471 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
472 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
473 // We are about to change the value of `index_reg` (see the
474 // calls to art::arm::Thumb2Assembler::Lsl and
475 // art::arm::Thumb2Assembler::AddConstant below), but it has
476 // not been saved by the previous call to
477 // art::SlowPathCode::SaveLiveRegisters, as it is a
478 // callee-save register --
479 // art::SlowPathCode::SaveLiveRegisters does not consider
480 // callee-save registers, as it has been designed with the
481 // assumption that callee-save registers are supposed to be
482 // handled by the called function. So, as a callee-save
483 // register, `index_reg` _would_ eventually be saved onto
484 // the stack, but it would be too late: we would have
485 // changed its value earlier. Therefore, we manually save
486 // it here into another freely available register,
487 // `free_reg`, chosen of course among the caller-save
488 // registers (as a callee-save `free_reg` register would
489 // exhibit the same problem).
490 //
491 // Note we could have requested a temporary register from
492 // the register allocator instead; but we prefer not to, as
493 // this is a slow path, and we know we can find a
494 // caller-save register that is available.
495 Register free_reg = FindAvailableCallerSaveRegister(codegen);
496 __ Mov(free_reg, index_reg);
497 index_reg = free_reg;
498 index = Location::RegisterLocation(index_reg);
499 } else {
500 // The initial register stored in `index_` has already been
501 // saved in the call to art::SlowPathCode::SaveLiveRegisters
502 // (as it is not a callee-save register), so we can freely
503 // use it.
504 }
505 // Shifting the index value contained in `index_reg` by the scale
506 // factor (2) cannot overflow in practice, as the runtime is
507 // unable to allocate object arrays with a size larger than
508 // 2^26 - 1 (that is, 2^28 - 4 bytes).
509 __ Lsl(index_reg, index_reg, TIMES_4);
510 static_assert(
511 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
512 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
513 __ AddConstant(index_reg, index_reg, offset_);
514 } else {
515 DCHECK(instruction_->IsInvoke());
516 DCHECK(instruction_->GetLocations()->Intrinsified());
517 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
518 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
519 << instruction_->AsInvoke()->GetIntrinsic();
520 DCHECK_EQ(offset_, 0U);
521 DCHECK(index_.IsRegisterPair());
522 // UnsafeGet's offset location is a register pair, the low
523 // part contains the correct offset.
524 index = index_.ToLow();
525 }
526 }
527
528 // We're moving two or three locations to locations that could
529 // overlap, so we need a parallel move resolver.
530 InvokeRuntimeCallingConvention calling_convention;
531 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
532 parallel_move.AddMove(ref_,
533 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
534 Primitive::kPrimNot,
535 nullptr);
536 parallel_move.AddMove(obj_,
537 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
538 Primitive::kPrimNot,
539 nullptr);
540 if (index.IsValid()) {
541 parallel_move.AddMove(index,
542 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
543 Primitive::kPrimInt,
544 nullptr);
545 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
546 } else {
547 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
548 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
549 }
550 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
551 instruction_,
552 instruction_->GetDexPc(),
553 this);
554 CheckEntrypointTypes<
555 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
556 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
557
558 RestoreLiveRegisters(codegen, locations);
559 __ b(GetExitLabel());
560 }
561
562 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
563
564 private:
565 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
566 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
567 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
568 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
569 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
570 return static_cast<Register>(i);
571 }
572 }
573 // We shall never fail to find a free caller-save register, as
574 // there are more than two core caller-save registers on ARM
575 // (meaning it is possible to find one which is different from
576 // `ref` and `obj`).
577 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
578 LOG(FATAL) << "Could not find a free caller-save register";
579 UNREACHABLE();
580 }
581
582 HInstruction* const instruction_;
583 const Location out_;
584 const Location ref_;
585 const Location obj_;
586 const uint32_t offset_;
587 // An additional location containing an index to an array.
588 // Only used for HArrayGet and the UnsafeGetObject &
589 // UnsafeGetObjectVolatile intrinsics.
590 const Location index_;
591
592 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
593};
594
595// Slow path generating a read barrier for a GC root.
596class ReadBarrierForRootSlowPathARM : public SlowPathCode {
597 public:
598 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
599 : instruction_(instruction), out_(out), root_(root) {}
600
601 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
602 LocationSummary* locations = instruction_->GetLocations();
603 Register reg_out = out_.AsRegister<Register>();
604 DCHECK(locations->CanCall());
605 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
606 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString());
607
608 __ Bind(GetEntryLabel());
609 SaveLiveRegisters(codegen, locations);
610
611 InvokeRuntimeCallingConvention calling_convention;
612 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
613 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
614 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
615 instruction_,
616 instruction_->GetDexPc(),
617 this);
618 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
619 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
620
621 RestoreLiveRegisters(codegen, locations);
622 __ b(GetExitLabel());
623 }
624
625 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
626
627 private:
628 HInstruction* const instruction_;
629 const Location out_;
630 const Location root_;
631
632 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
633};
634
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000635#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100636#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700637
Aart Bike9f37602015-10-09 11:15:55 -0700638inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700639 switch (cond) {
640 case kCondEQ: return EQ;
641 case kCondNE: return NE;
642 case kCondLT: return LT;
643 case kCondLE: return LE;
644 case kCondGT: return GT;
645 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700646 case kCondB: return LO;
647 case kCondBE: return LS;
648 case kCondA: return HI;
649 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700650 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100651 LOG(FATAL) << "Unreachable";
652 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700653}
654
Aart Bike9f37602015-10-09 11:15:55 -0700655// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100656inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700657 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100658 case kCondEQ: return EQ;
659 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700660 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100661 case kCondLT: return LO;
662 case kCondLE: return LS;
663 case kCondGT: return HI;
664 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700665 // Unsigned remain unchanged.
666 case kCondB: return LO;
667 case kCondBE: return LS;
668 case kCondA: return HI;
669 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700670 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100671 LOG(FATAL) << "Unreachable";
672 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700673}
674
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100675void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100676 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100677}
678
679void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100680 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100681}
682
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100683size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
684 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
685 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100686}
687
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100688size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
689 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
690 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100691}
692
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000693size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
694 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
695 return kArmWordSize;
696}
697
698size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
699 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
700 return kArmWordSize;
701}
702
Calin Juravle34166012014-12-19 17:22:29 +0000703CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000704 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100705 const CompilerOptions& compiler_options,
706 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000707 : CodeGenerator(graph,
708 kNumberOfCoreRegisters,
709 kNumberOfSRegisters,
710 kNumberOfRegisterPairs,
711 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
712 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000713 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
714 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100715 compiler_options,
716 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100717 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100718 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100719 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100720 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000721 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000722 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100723 method_patches_(MethodReferenceComparator(),
724 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
725 call_patches_(MethodReferenceComparator(),
726 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
727 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700728 // Always save the LR register to mimic Quick.
729 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100730}
731
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000732void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
733 // Ensure that we fix up branches and literal loads and emit the literal pool.
734 __ FinalizeCode();
735
736 // Adjust native pc offsets in stack maps.
737 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
738 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
739 uint32_t new_position = __ GetAdjustedPosition(old_position);
740 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
741 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100742 // Adjust pc offsets for the disassembly information.
743 if (disasm_info_ != nullptr) {
744 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
745 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
746 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
747 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
748 it.second.start = __ GetAdjustedPosition(it.second.start);
749 it.second.end = __ GetAdjustedPosition(it.second.end);
750 }
751 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
752 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
753 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
754 }
755 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000756
757 CodeGenerator::Finalize(allocator);
758}
759
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100760Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100761 switch (type) {
762 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100763 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100764 ArmManagedRegister pair =
765 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100766 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
767 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
768
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100769 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
770 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100771 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100772 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100773 }
774
775 case Primitive::kPrimByte:
776 case Primitive::kPrimBoolean:
777 case Primitive::kPrimChar:
778 case Primitive::kPrimShort:
779 case Primitive::kPrimInt:
780 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100781 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100782 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100783 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
784 ArmManagedRegister current =
785 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
786 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100787 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100788 }
789 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100790 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100791 }
792
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000793 case Primitive::kPrimFloat: {
794 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100795 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100796 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100797
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000798 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000799 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
800 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000801 return Location::FpuRegisterPairLocation(reg, reg + 1);
802 }
803
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100804 case Primitive::kPrimVoid:
805 LOG(FATAL) << "Unreachable type " << type;
806 }
807
Roland Levillain3b359c72015-11-17 19:35:12 +0000808 return Location::NoLocation();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100809}
810
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000811void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100812 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100813 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100814
815 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100816 blocked_core_registers_[SP] = true;
817 blocked_core_registers_[LR] = true;
818 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100819
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100820 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100821 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100822
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100823 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100824 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100825
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000826 if (is_baseline) {
827 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
828 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
829 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000830
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000831 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100832 }
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000833
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100834 if (is_baseline || GetGraph()->IsDebuggable()) {
835 // Stubs do not save callee-save floating point registers. If the graph
836 // is debuggable, we need to deal with these registers differently. For
837 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000838 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
839 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
840 }
841 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100842
843 UpdateBlockedPairRegisters();
844}
845
846void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
847 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
848 ArmManagedRegister current =
849 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
850 if (blocked_core_registers_[current.AsRegisterPairLow()]
851 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
852 blocked_register_pairs_[i] = true;
853 }
854 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100855}
856
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100857InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
858 : HGraphVisitor(graph),
859 assembler_(codegen->GetAssembler()),
860 codegen_(codegen) {}
861
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000862void CodeGeneratorARM::ComputeSpillMask() {
863 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000864 // Save one extra register for baseline. Note that on thumb2, there is no easy
865 // instruction to restore just the PC, so this actually helps both baseline
866 // and non-baseline to save and restore at least two registers at entry and exit.
867 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000868 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
869 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
870 // We use vpush and vpop for saving and restoring floating point registers, which take
871 // a SRegister and the number of registers to save/restore after that SRegister. We
872 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
873 // but in the range.
874 if (fpu_spill_mask_ != 0) {
875 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
876 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
877 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
878 fpu_spill_mask_ |= (1 << i);
879 }
880 }
881}
882
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100883static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100884 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100885}
886
887static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100888 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100889}
890
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000891void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000892 bool skip_overflow_check =
893 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000894 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000895 __ Bind(&frame_entry_label_);
896
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000897 if (HasEmptyFrame()) {
898 return;
899 }
900
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100901 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000902 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
903 __ LoadFromOffset(kLoadWord, IP, IP, 0);
904 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100905 }
906
Andreas Gampe501fd632015-09-10 16:11:06 -0700907 __ PushList(core_spill_mask_);
908 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
909 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000910 if (fpu_spill_mask_ != 0) {
911 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
912 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100913 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100914 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000915 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100916 int adjust = GetFrameSize() - FrameEntrySpillSize();
917 __ AddConstant(SP, -adjust);
918 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100919 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000920}
921
922void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000923 if (HasEmptyFrame()) {
924 __ bx(LR);
925 return;
926 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100927 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100928 int adjust = GetFrameSize() - FrameEntrySpillSize();
929 __ AddConstant(SP, adjust);
930 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000931 if (fpu_spill_mask_ != 0) {
932 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
933 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100934 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
935 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000936 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700937 // Pop LR into PC to return.
938 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
939 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
940 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100941 __ cfi().RestoreState();
942 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000943}
944
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100945void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700946 Label* label = GetLabelOf(block);
947 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000948}
949
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100950Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
951 switch (load->GetType()) {
952 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100953 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100954 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100955
956 case Primitive::kPrimInt:
957 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100958 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100959 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100960
961 case Primitive::kPrimBoolean:
962 case Primitive::kPrimByte:
963 case Primitive::kPrimChar:
964 case Primitive::kPrimShort:
965 case Primitive::kPrimVoid:
966 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700967 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100968 }
969
970 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700971 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100972}
973
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100974Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100975 switch (type) {
976 case Primitive::kPrimBoolean:
977 case Primitive::kPrimByte:
978 case Primitive::kPrimChar:
979 case Primitive::kPrimShort:
980 case Primitive::kPrimInt:
981 case Primitive::kPrimNot: {
982 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000983 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100984 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100985 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100986 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000987 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100988 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100989 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100990
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000991 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100992 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000993 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100994 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000995 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100996 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000997 if (calling_convention.GetRegisterAt(index) == R1) {
998 // Skip R1, and use R2_R3 instead.
999 gp_index_++;
1000 index++;
1001 }
1002 }
1003 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1004 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001005 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001006
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001007 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001008 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001009 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001010 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1011 }
1012 }
1013
1014 case Primitive::kPrimFloat: {
1015 uint32_t stack_index = stack_index_++;
1016 if (float_index_ % 2 == 0) {
1017 float_index_ = std::max(double_index_, float_index_);
1018 }
1019 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1020 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1021 } else {
1022 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1023 }
1024 }
1025
1026 case Primitive::kPrimDouble: {
1027 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1028 uint32_t stack_index = stack_index_;
1029 stack_index_ += 2;
1030 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1031 uint32_t index = double_index_;
1032 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001033 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001034 calling_convention.GetFpuRegisterAt(index),
1035 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001036 DCHECK(ExpectedPairLayout(result));
1037 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001038 } else {
1039 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001040 }
1041 }
1042
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001043 case Primitive::kPrimVoid:
1044 LOG(FATAL) << "Unexpected parameter type " << type;
1045 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001046 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001047 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001048}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001049
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001050Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001051 switch (type) {
1052 case Primitive::kPrimBoolean:
1053 case Primitive::kPrimByte:
1054 case Primitive::kPrimChar:
1055 case Primitive::kPrimShort:
1056 case Primitive::kPrimInt:
1057 case Primitive::kPrimNot: {
1058 return Location::RegisterLocation(R0);
1059 }
1060
1061 case Primitive::kPrimFloat: {
1062 return Location::FpuRegisterLocation(S0);
1063 }
1064
1065 case Primitive::kPrimLong: {
1066 return Location::RegisterPairLocation(R0, R1);
1067 }
1068
1069 case Primitive::kPrimDouble: {
1070 return Location::FpuRegisterPairLocation(S0, S1);
1071 }
1072
1073 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001074 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001075 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001076
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001077 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001078}
1079
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001080Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1081 return Location::RegisterLocation(kMethodRegisterArgument);
1082}
1083
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001084void CodeGeneratorARM::Move32(Location destination, Location source) {
1085 if (source.Equals(destination)) {
1086 return;
1087 }
1088 if (destination.IsRegister()) {
1089 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001090 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001091 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001092 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001093 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001094 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001095 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 } else if (destination.IsFpuRegister()) {
1097 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001098 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001099 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001100 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001101 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001104 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001105 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001107 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001108 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001110 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001111 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001112 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1113 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001114 }
1115 }
1116}
1117
1118void CodeGeneratorARM::Move64(Location destination, Location source) {
1119 if (source.Equals(destination)) {
1120 return;
1121 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001122 if (destination.IsRegisterPair()) {
1123 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001124 EmitParallelMoves(
1125 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1126 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001127 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001128 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001129 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1130 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001131 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001132 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001133 } else if (source.IsFpuRegisterPair()) {
1134 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1135 destination.AsRegisterPairHigh<Register>(),
1136 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001137 } else {
1138 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001139 DCHECK(ExpectedPairLayout(destination));
1140 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1141 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001142 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001143 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001144 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001145 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1146 SP,
1147 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001148 } else if (source.IsRegisterPair()) {
1149 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1150 source.AsRegisterPairLow<Register>(),
1151 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001152 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001153 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001154 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001155 } else {
1156 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001157 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001158 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001159 if (source.AsRegisterPairLow<Register>() == R1) {
1160 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001161 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1162 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001163 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001164 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001165 SP, destination.GetStackIndex());
1166 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001167 } else if (source.IsFpuRegisterPair()) {
1168 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1169 SP,
1170 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001171 } else {
1172 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001173 EmitParallelMoves(
1174 Location::StackSlot(source.GetStackIndex()),
1175 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001176 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001177 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001178 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1179 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001180 }
1181 }
1182}
1183
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001184void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001185 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001186 if (instruction->IsCurrentMethod()) {
1187 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
1188 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001189 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001190 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001191 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001192 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
1193 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +00001194 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001195 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001196 } else {
1197 DCHECK(location.IsStackSlot());
1198 __ LoadImmediate(IP, value);
1199 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1200 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001201 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +00001202 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +00001203 int64_t value = const_to_move->AsLongConstant()->GetValue();
1204 if (location.IsRegisterPair()) {
1205 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
1206 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
1207 } else {
1208 DCHECK(location.IsDoubleStackSlot());
1209 __ LoadImmediate(IP, Low32Bits(value));
1210 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1211 __ LoadImmediate(IP, High32Bits(value));
1212 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
1213 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001214 }
Roland Levillain476df552014-10-09 17:51:36 +01001215 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001216 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
1217 switch (instruction->GetType()) {
1218 case Primitive::kPrimBoolean:
1219 case Primitive::kPrimByte:
1220 case Primitive::kPrimChar:
1221 case Primitive::kPrimShort:
1222 case Primitive::kPrimInt:
1223 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001224 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001225 Move32(location, Location::StackSlot(stack_slot));
1226 break;
1227
1228 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001229 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001230 Move64(location, Location::DoubleStackSlot(stack_slot));
1231 break;
1232
1233 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001234 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001235 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001236 } else if (instruction->IsTemporary()) {
1237 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +00001238 if (temp_location.IsStackSlot()) {
1239 Move32(location, temp_location);
1240 } else {
1241 DCHECK(temp_location.IsDoubleStackSlot());
1242 Move64(location, temp_location);
1243 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001244 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001245 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001246 switch (instruction->GetType()) {
1247 case Primitive::kPrimBoolean:
1248 case Primitive::kPrimByte:
1249 case Primitive::kPrimChar:
1250 case Primitive::kPrimShort:
1251 case Primitive::kPrimNot:
1252 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001253 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001254 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001255 break;
1256
1257 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001258 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001259 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001260 break;
1261
1262 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001263 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001264 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001265 }
1266}
1267
Calin Juravle175dc732015-08-25 15:42:32 +01001268void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1269 DCHECK(location.IsRegister());
1270 __ LoadImmediate(location.AsRegister<Register>(), value);
1271}
1272
Calin Juravlee460d1d2015-09-29 04:52:17 +01001273void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1274 if (Primitive::Is64BitType(dst_type)) {
1275 Move64(dst, src);
1276 } else {
1277 Move32(dst, src);
1278 }
1279}
1280
1281void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1282 if (location.IsRegister()) {
1283 locations->AddTemp(location);
1284 } else if (location.IsRegisterPair()) {
1285 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1286 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1287 } else {
1288 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1289 }
1290}
1291
Calin Juravle175dc732015-08-25 15:42:32 +01001292void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1293 HInstruction* instruction,
1294 uint32_t dex_pc,
1295 SlowPathCode* slow_path) {
1296 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1297 instruction,
1298 dex_pc,
1299 slow_path);
1300}
1301
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001302void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1303 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001304 uint32_t dex_pc,
1305 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001306 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001307 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1308 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001309 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001310}
1311
David Brazdilfc6a86a2015-06-26 10:33:45 +00001312void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001313 DCHECK(!successor->IsExitBlock());
1314
1315 HBasicBlock* block = got->GetBlock();
1316 HInstruction* previous = got->GetPrevious();
1317
1318 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001319 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001320 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1321 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1322 return;
1323 }
1324
1325 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1326 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1327 }
1328 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001329 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001330 }
1331}
1332
David Brazdilfc6a86a2015-06-26 10:33:45 +00001333void LocationsBuilderARM::VisitGoto(HGoto* got) {
1334 got->SetLocations(nullptr);
1335}
1336
1337void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1338 HandleGoto(got, got->GetSuccessor());
1339}
1340
1341void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1342 try_boundary->SetLocations(nullptr);
1343}
1344
1345void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1346 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1347 if (!successor->IsExitBlock()) {
1348 HandleGoto(try_boundary, successor);
1349 }
1350}
1351
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001352void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001353 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001354}
1355
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001356void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001357}
1358
Roland Levillain4fa13f62015-07-06 18:11:54 +01001359void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1360 ShifterOperand operand;
1361 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1362 __ cmp(left, operand);
1363 } else {
1364 Register temp = IP;
1365 __ LoadImmediate(temp, right);
1366 __ cmp(left, ShifterOperand(temp));
1367 }
1368}
1369
1370void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1371 Label* true_label,
1372 Label* false_label) {
1373 __ vmstat(); // transfer FP status register to ARM APSR.
Aart Bike9f37602015-10-09 11:15:55 -07001374 // TODO: merge into a single branch (except "equal or unordered" and "not equal")
Roland Levillain4fa13f62015-07-06 18:11:54 +01001375 if (cond->IsFPConditionTrueIfNaN()) {
1376 __ b(true_label, VS); // VS for unordered.
1377 } else if (cond->IsFPConditionFalseIfNaN()) {
1378 __ b(false_label, VS); // VS for unordered.
1379 }
Aart Bike9f37602015-10-09 11:15:55 -07001380 __ b(true_label, ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001381}
1382
1383void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1384 Label* true_label,
1385 Label* false_label) {
1386 LocationSummary* locations = cond->GetLocations();
1387 Location left = locations->InAt(0);
1388 Location right = locations->InAt(1);
1389 IfCondition if_cond = cond->GetCondition();
1390
1391 Register left_high = left.AsRegisterPairHigh<Register>();
1392 Register left_low = left.AsRegisterPairLow<Register>();
1393 IfCondition true_high_cond = if_cond;
1394 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001395 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001396
1397 // Set the conditions for the test, remembering that == needs to be
1398 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001399 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001400 switch (if_cond) {
1401 case kCondEQ:
1402 case kCondNE:
1403 // Nothing to do.
1404 break;
1405 case kCondLT:
1406 false_high_cond = kCondGT;
1407 break;
1408 case kCondLE:
1409 true_high_cond = kCondLT;
1410 break;
1411 case kCondGT:
1412 false_high_cond = kCondLT;
1413 break;
1414 case kCondGE:
1415 true_high_cond = kCondGT;
1416 break;
Aart Bike9f37602015-10-09 11:15:55 -07001417 case kCondB:
1418 false_high_cond = kCondA;
1419 break;
1420 case kCondBE:
1421 true_high_cond = kCondB;
1422 break;
1423 case kCondA:
1424 false_high_cond = kCondB;
1425 break;
1426 case kCondAE:
1427 true_high_cond = kCondA;
1428 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001429 }
1430 if (right.IsConstant()) {
1431 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1432 int32_t val_low = Low32Bits(value);
1433 int32_t val_high = High32Bits(value);
1434
1435 GenerateCompareWithImmediate(left_high, val_high);
1436 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001437 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001438 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001439 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001440 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001441 __ b(true_label, ARMCondition(true_high_cond));
1442 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001443 }
1444 // Must be equal high, so compare the lows.
1445 GenerateCompareWithImmediate(left_low, val_low);
1446 } else {
1447 Register right_high = right.AsRegisterPairHigh<Register>();
1448 Register right_low = right.AsRegisterPairLow<Register>();
1449
1450 __ cmp(left_high, ShifterOperand(right_high));
1451 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001452 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001453 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001454 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001455 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001456 __ b(true_label, ARMCondition(true_high_cond));
1457 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001458 }
1459 // Must be equal high, so compare the lows.
1460 __ cmp(left_low, ShifterOperand(right_low));
1461 }
1462 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001463 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001464 __ b(true_label, final_condition);
1465}
1466
David Brazdil0debae72015-11-12 18:37:00 +00001467void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1468 Label* true_target_in,
1469 Label* false_target_in) {
1470 // Generated branching requires both targets to be explicit. If either of the
1471 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1472 Label fallthrough_target;
1473 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1474 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1475
Roland Levillain4fa13f62015-07-06 18:11:54 +01001476 LocationSummary* locations = condition->GetLocations();
1477 Location left = locations->InAt(0);
1478 Location right = locations->InAt(1);
1479
Roland Levillain4fa13f62015-07-06 18:11:54 +01001480 Primitive::Type type = condition->InputAt(0)->GetType();
1481 switch (type) {
1482 case Primitive::kPrimLong:
1483 GenerateLongComparesAndJumps(condition, true_target, false_target);
1484 break;
1485 case Primitive::kPrimFloat:
1486 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1487 GenerateFPJumps(condition, true_target, false_target);
1488 break;
1489 case Primitive::kPrimDouble:
1490 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1491 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1492 GenerateFPJumps(condition, true_target, false_target);
1493 break;
1494 default:
1495 LOG(FATAL) << "Unexpected compare type " << type;
1496 }
1497
David Brazdil0debae72015-11-12 18:37:00 +00001498 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001499 __ b(false_target);
1500 }
David Brazdil0debae72015-11-12 18:37:00 +00001501
1502 if (fallthrough_target.IsLinked()) {
1503 __ Bind(&fallthrough_target);
1504 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001505}
1506
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001507void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001508 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001509 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001510 Label* false_target) {
1511 HInstruction* cond = instruction->InputAt(condition_input_index);
1512
1513 if (true_target == nullptr && false_target == nullptr) {
1514 // Nothing to do. The code always falls through.
1515 return;
1516 } else if (cond->IsIntConstant()) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001517 // Constant condition, statically compared against 1.
David Brazdil0debae72015-11-12 18:37:00 +00001518 if (cond->AsIntConstant()->IsOne()) {
1519 if (true_target != nullptr) {
1520 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001521 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001522 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001523 DCHECK(cond->AsIntConstant()->IsZero());
1524 if (false_target != nullptr) {
1525 __ b(false_target);
1526 }
1527 }
1528 return;
1529 }
1530
1531 // The following code generates these patterns:
1532 // (1) true_target == nullptr && false_target != nullptr
1533 // - opposite condition true => branch to false_target
1534 // (2) true_target != nullptr && false_target == nullptr
1535 // - condition true => branch to true_target
1536 // (3) true_target != nullptr && false_target != nullptr
1537 // - condition true => branch to true_target
1538 // - branch to false_target
1539 if (IsBooleanValueOrMaterializedCondition(cond)) {
1540 // Condition has been materialized, compare the output to 0.
1541 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1542 DCHECK(cond_val.IsRegister());
1543 if (true_target == nullptr) {
1544 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1545 } else {
1546 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001547 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001548 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001549 // Condition has not been materialized. Use its inputs as the comparison and
1550 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001551 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001552
1553 // If this is a long or FP comparison that has been folded into
1554 // the HCondition, generate the comparison directly.
1555 Primitive::Type type = condition->InputAt(0)->GetType();
1556 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1557 GenerateCompareTestAndBranch(condition, true_target, false_target);
1558 return;
1559 }
1560
1561 LocationSummary* locations = cond->GetLocations();
1562 DCHECK(locations->InAt(0).IsRegister());
1563 Register left = locations->InAt(0).AsRegister<Register>();
1564 Location right = locations->InAt(1);
1565 if (right.IsRegister()) {
1566 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001567 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001568 DCHECK(right.IsConstant());
1569 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1570 }
1571 if (true_target == nullptr) {
1572 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1573 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001574 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001575 }
Dave Allison20dfc792014-06-16 20:44:29 -07001576 }
David Brazdil0debae72015-11-12 18:37:00 +00001577
1578 // If neither branch falls through (case 3), the conditional branch to `true_target`
1579 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1580 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001581 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001582 }
1583}
1584
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001585void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001586 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1587 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001588 locations->SetInAt(0, Location::RequiresRegister());
1589 }
1590}
1591
1592void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001593 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1594 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1595 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1596 nullptr : codegen_->GetLabelOf(true_successor);
1597 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1598 nullptr : codegen_->GetLabelOf(false_successor);
1599 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001600}
1601
1602void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1603 LocationSummary* locations = new (GetGraph()->GetArena())
1604 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001605 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001606 locations->SetInAt(0, Location::RequiresRegister());
1607 }
1608}
1609
1610void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
David Brazdil0debae72015-11-12 18:37:00 +00001611 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DeoptimizationSlowPathARM(deoptimize);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001612 codegen_->AddSlowPath(slow_path);
David Brazdil0debae72015-11-12 18:37:00 +00001613 GenerateTestAndBranch(deoptimize,
1614 /* condition_input_index */ 0,
1615 slow_path->GetEntryLabel(),
1616 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001617}
Dave Allison20dfc792014-06-16 20:44:29 -07001618
Roland Levillain0d37cd02015-05-27 16:39:19 +01001619void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001620 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001621 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001622 // Handle the long/FP comparisons made in instruction simplification.
1623 switch (cond->InputAt(0)->GetType()) {
1624 case Primitive::kPrimLong:
1625 locations->SetInAt(0, Location::RequiresRegister());
1626 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1627 if (cond->NeedsMaterialization()) {
1628 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1629 }
1630 break;
1631
1632 case Primitive::kPrimFloat:
1633 case Primitive::kPrimDouble:
1634 locations->SetInAt(0, Location::RequiresFpuRegister());
1635 locations->SetInAt(1, Location::RequiresFpuRegister());
1636 if (cond->NeedsMaterialization()) {
1637 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1638 }
1639 break;
1640
1641 default:
1642 locations->SetInAt(0, Location::RequiresRegister());
1643 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1644 if (cond->NeedsMaterialization()) {
1645 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1646 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001647 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001648}
1649
Roland Levillain0d37cd02015-05-27 16:39:19 +01001650void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001651 if (!cond->NeedsMaterialization()) {
1652 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001653 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001654
1655 LocationSummary* locations = cond->GetLocations();
1656 Location left = locations->InAt(0);
1657 Location right = locations->InAt(1);
1658 Register out = locations->Out().AsRegister<Register>();
1659 Label true_label, false_label;
1660
1661 switch (cond->InputAt(0)->GetType()) {
1662 default: {
1663 // Integer case.
1664 if (right.IsRegister()) {
1665 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1666 } else {
1667 DCHECK(right.IsConstant());
1668 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1669 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1670 }
Aart Bike9f37602015-10-09 11:15:55 -07001671 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001672 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001673 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001674 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001675 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001676 return;
1677 }
1678 case Primitive::kPrimLong:
1679 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1680 break;
1681 case Primitive::kPrimFloat:
1682 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1683 GenerateFPJumps(cond, &true_label, &false_label);
1684 break;
1685 case Primitive::kPrimDouble:
1686 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1687 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1688 GenerateFPJumps(cond, &true_label, &false_label);
1689 break;
1690 }
1691
1692 // Convert the jumps into the result.
1693 Label done_label;
1694
1695 // False case: result = 0.
1696 __ Bind(&false_label);
1697 __ LoadImmediate(out, 0);
1698 __ b(&done_label);
1699
1700 // True case: result = 1.
1701 __ Bind(&true_label);
1702 __ LoadImmediate(out, 1);
1703 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001704}
1705
1706void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1707 VisitCondition(comp);
1708}
1709
1710void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1711 VisitCondition(comp);
1712}
1713
1714void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1715 VisitCondition(comp);
1716}
1717
1718void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1719 VisitCondition(comp);
1720}
1721
1722void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1723 VisitCondition(comp);
1724}
1725
1726void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1727 VisitCondition(comp);
1728}
1729
1730void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1731 VisitCondition(comp);
1732}
1733
1734void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1735 VisitCondition(comp);
1736}
1737
1738void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1739 VisitCondition(comp);
1740}
1741
1742void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1743 VisitCondition(comp);
1744}
1745
1746void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1747 VisitCondition(comp);
1748}
1749
1750void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1751 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001752}
1753
Aart Bike9f37602015-10-09 11:15:55 -07001754void LocationsBuilderARM::VisitBelow(HBelow* comp) {
1755 VisitCondition(comp);
1756}
1757
1758void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
1759 VisitCondition(comp);
1760}
1761
1762void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1763 VisitCondition(comp);
1764}
1765
1766void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1767 VisitCondition(comp);
1768}
1769
1770void LocationsBuilderARM::VisitAbove(HAbove* comp) {
1771 VisitCondition(comp);
1772}
1773
1774void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
1775 VisitCondition(comp);
1776}
1777
1778void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1779 VisitCondition(comp);
1780}
1781
1782void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1783 VisitCondition(comp);
1784}
1785
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001786void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001787 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001788}
1789
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001790void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1791 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001792}
1793
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001794void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001795 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001796}
1797
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001798void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001799 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001800}
1801
1802void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001803 LocationSummary* locations =
1804 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001805 switch (store->InputAt(1)->GetType()) {
1806 case Primitive::kPrimBoolean:
1807 case Primitive::kPrimByte:
1808 case Primitive::kPrimChar:
1809 case Primitive::kPrimShort:
1810 case Primitive::kPrimInt:
1811 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001812 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001813 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1814 break;
1815
1816 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001817 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001818 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1819 break;
1820
1821 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001822 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001823 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001824}
1825
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001826void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001827}
1828
1829void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001830 LocationSummary* locations =
1831 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001832 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001833}
1834
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001835void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001836 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001837}
1838
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001839void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1840 LocationSummary* locations =
1841 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1842 locations->SetOut(Location::ConstantLocation(constant));
1843}
1844
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001845void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001846 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001847}
1848
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001849void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001850 LocationSummary* locations =
1851 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001852 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001853}
1854
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001855void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001856 // Will be generated at use site.
1857}
1858
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001859void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1860 LocationSummary* locations =
1861 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1862 locations->SetOut(Location::ConstantLocation(constant));
1863}
1864
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001865void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001866 // Will be generated at use site.
1867}
1868
1869void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1870 LocationSummary* locations =
1871 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1872 locations->SetOut(Location::ConstantLocation(constant));
1873}
1874
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001875void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001876 // Will be generated at use site.
1877}
1878
Calin Juravle27df7582015-04-17 19:12:31 +01001879void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1880 memory_barrier->SetLocations(nullptr);
1881}
1882
1883void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1884 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1885}
1886
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001887void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001888 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001889}
1890
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001891void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001892 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001893}
1894
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001895void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001896 LocationSummary* locations =
1897 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001898 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001899}
1900
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001901void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001902 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001903}
1904
Calin Juravle175dc732015-08-25 15:42:32 +01001905void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1906 // The trampoline uses the same calling convention as dex calling conventions,
1907 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1908 // the method_idx.
1909 HandleInvoke(invoke);
1910}
1911
1912void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1913 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1914}
1915
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001916void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001917 // When we do not run baseline, explicit clinit checks triggered by static
1918 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1919 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001920
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001921 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001922 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001923 codegen_->GetInstructionSetFeatures());
1924 if (intrinsic.TryDispatch(invoke)) {
1925 return;
1926 }
1927
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001928 HandleInvoke(invoke);
1929}
1930
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001931static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1932 if (invoke->GetLocations()->Intrinsified()) {
1933 IntrinsicCodeGeneratorARM intrinsic(codegen);
1934 intrinsic.Dispatch(invoke);
1935 return true;
1936 }
1937 return false;
1938}
1939
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001940void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001941 // When we do not run baseline, explicit clinit checks triggered by static
1942 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1943 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001944
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001945 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1946 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001947 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001948
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001949 LocationSummary* locations = invoke->GetLocations();
1950 codegen_->GenerateStaticOrDirectCall(
1951 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001952 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001953}
1954
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001955void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001956 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001957 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001958}
1959
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001960void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001961 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001962 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001963 codegen_->GetInstructionSetFeatures());
1964 if (intrinsic.TryDispatch(invoke)) {
1965 return;
1966 }
1967
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001968 HandleInvoke(invoke);
1969}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001970
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001971void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001972 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1973 return;
1974 }
1975
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001976 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001977 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001978 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001979}
1980
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001981void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1982 HandleInvoke(invoke);
1983 // Add the hidden argument.
1984 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1985}
1986
1987void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1988 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001989 LocationSummary* locations = invoke->GetLocations();
1990 Register temp = locations->GetTemp(0).AsRegister<Register>();
1991 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001992 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1993 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001994 Location receiver = locations->InAt(0);
1995 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1996
Roland Levillain3b359c72015-11-17 19:35:12 +00001997 // Set the hidden argument. This is safe to do this here, as R12
1998 // won't be modified thereafter, before the `blx` (call) instruction.
1999 DCHECK_EQ(R12, hidden_reg);
2000 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002001
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002002 if (receiver.IsStackSlot()) {
2003 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00002004 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002005 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
2006 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00002007 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002008 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002009 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002010 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00002011 // Instead of simply (possibly) unpoisoning `temp` here, we should
2012 // emit a read barrier for the previous class reference load.
2013 // However this is not required in practice, as this is an
2014 // intermediate/temporary reference and because the current
2015 // concurrent copying collector keeps the from-space memory
2016 // intact/accessible until the end of the marking phase (the
2017 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002018 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002019 // temp = temp->GetImtEntryAt(method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00002020 uint32_t entry_point =
2021 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002022 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
2023 // LR = temp->GetEntryPoint();
2024 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
2025 // LR();
2026 __ blx(LR);
2027 DCHECK(!codegen_->IsLeafMethod());
2028 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2029}
2030
Roland Levillain88cb1752014-10-20 16:36:47 +01002031void LocationsBuilderARM::VisitNeg(HNeg* neg) {
2032 LocationSummary* locations =
2033 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2034 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002035 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01002036 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002037 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2038 break;
2039 }
2040 case Primitive::kPrimLong: {
2041 locations->SetInAt(0, Location::RequiresRegister());
2042 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002043 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002044 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002045
Roland Levillain88cb1752014-10-20 16:36:47 +01002046 case Primitive::kPrimFloat:
2047 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002048 locations->SetInAt(0, Location::RequiresFpuRegister());
2049 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002050 break;
2051
2052 default:
2053 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2054 }
2055}
2056
2057void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2058 LocationSummary* locations = neg->GetLocations();
2059 Location out = locations->Out();
2060 Location in = locations->InAt(0);
2061 switch (neg->GetResultType()) {
2062 case Primitive::kPrimInt:
2063 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002064 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01002065 break;
2066
2067 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002068 DCHECK(in.IsRegisterPair());
2069 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2070 __ rsbs(out.AsRegisterPairLow<Register>(),
2071 in.AsRegisterPairLow<Register>(),
2072 ShifterOperand(0));
2073 // We cannot emit an RSC (Reverse Subtract with Carry)
2074 // instruction here, as it does not exist in the Thumb-2
2075 // instruction set. We use the following approach
2076 // using SBC and SUB instead.
2077 //
2078 // out.hi = -C
2079 __ sbc(out.AsRegisterPairHigh<Register>(),
2080 out.AsRegisterPairHigh<Register>(),
2081 ShifterOperand(out.AsRegisterPairHigh<Register>()));
2082 // out.hi = out.hi - in.hi
2083 __ sub(out.AsRegisterPairHigh<Register>(),
2084 out.AsRegisterPairHigh<Register>(),
2085 ShifterOperand(in.AsRegisterPairHigh<Register>()));
2086 break;
2087
Roland Levillain88cb1752014-10-20 16:36:47 +01002088 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002089 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002090 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002091 break;
2092
Roland Levillain88cb1752014-10-20 16:36:47 +01002093 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002094 DCHECK(in.IsFpuRegisterPair());
2095 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2096 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01002097 break;
2098
2099 default:
2100 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2101 }
2102}
2103
Roland Levillaindff1f282014-11-05 14:15:05 +00002104void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002105 Primitive::Type result_type = conversion->GetResultType();
2106 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002107 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002108
Roland Levillain5b3ee562015-04-14 16:02:41 +01002109 // The float-to-long, double-to-long and long-to-float type conversions
2110 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002111 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002112 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2113 && result_type == Primitive::kPrimLong)
2114 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002115 ? LocationSummary::kCall
2116 : LocationSummary::kNoCall;
2117 LocationSummary* locations =
2118 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2119
David Brazdilb2bd1c52015-03-25 11:17:37 +00002120 // The Java language does not allow treating boolean as an integral type but
2121 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002122
Roland Levillaindff1f282014-11-05 14:15:05 +00002123 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002124 case Primitive::kPrimByte:
2125 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002126 case Primitive::kPrimBoolean:
2127 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002128 case Primitive::kPrimShort:
2129 case Primitive::kPrimInt:
2130 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002131 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002132 locations->SetInAt(0, Location::RequiresRegister());
2133 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2134 break;
2135
2136 default:
2137 LOG(FATAL) << "Unexpected type conversion from " << input_type
2138 << " to " << result_type;
2139 }
2140 break;
2141
Roland Levillain01a8d712014-11-14 16:27:39 +00002142 case Primitive::kPrimShort:
2143 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002144 case Primitive::kPrimBoolean:
2145 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002146 case Primitive::kPrimByte:
2147 case Primitive::kPrimInt:
2148 case Primitive::kPrimChar:
2149 // Processing a Dex `int-to-short' instruction.
2150 locations->SetInAt(0, Location::RequiresRegister());
2151 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2152 break;
2153
2154 default:
2155 LOG(FATAL) << "Unexpected type conversion from " << input_type
2156 << " to " << result_type;
2157 }
2158 break;
2159
Roland Levillain946e1432014-11-11 17:35:19 +00002160 case Primitive::kPrimInt:
2161 switch (input_type) {
2162 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002163 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002164 locations->SetInAt(0, Location::Any());
2165 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2166 break;
2167
2168 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002169 // Processing a Dex `float-to-int' instruction.
2170 locations->SetInAt(0, Location::RequiresFpuRegister());
2171 locations->SetOut(Location::RequiresRegister());
2172 locations->AddTemp(Location::RequiresFpuRegister());
2173 break;
2174
Roland Levillain946e1432014-11-11 17:35:19 +00002175 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002176 // Processing a Dex `double-to-int' instruction.
2177 locations->SetInAt(0, Location::RequiresFpuRegister());
2178 locations->SetOut(Location::RequiresRegister());
2179 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002180 break;
2181
2182 default:
2183 LOG(FATAL) << "Unexpected type conversion from " << input_type
2184 << " to " << result_type;
2185 }
2186 break;
2187
Roland Levillaindff1f282014-11-05 14:15:05 +00002188 case Primitive::kPrimLong:
2189 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002190 case Primitive::kPrimBoolean:
2191 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002192 case Primitive::kPrimByte:
2193 case Primitive::kPrimShort:
2194 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002195 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002196 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002197 locations->SetInAt(0, Location::RequiresRegister());
2198 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2199 break;
2200
Roland Levillain624279f2014-12-04 11:54:28 +00002201 case Primitive::kPrimFloat: {
2202 // Processing a Dex `float-to-long' instruction.
2203 InvokeRuntimeCallingConvention calling_convention;
2204 locations->SetInAt(0, Location::FpuRegisterLocation(
2205 calling_convention.GetFpuRegisterAt(0)));
2206 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2207 break;
2208 }
2209
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002210 case Primitive::kPrimDouble: {
2211 // Processing a Dex `double-to-long' instruction.
2212 InvokeRuntimeCallingConvention calling_convention;
2213 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2214 calling_convention.GetFpuRegisterAt(0),
2215 calling_convention.GetFpuRegisterAt(1)));
2216 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002217 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002218 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002219
2220 default:
2221 LOG(FATAL) << "Unexpected type conversion from " << input_type
2222 << " to " << result_type;
2223 }
2224 break;
2225
Roland Levillain981e4542014-11-14 11:47:14 +00002226 case Primitive::kPrimChar:
2227 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002228 case Primitive::kPrimBoolean:
2229 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002230 case Primitive::kPrimByte:
2231 case Primitive::kPrimShort:
2232 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002233 // Processing a Dex `int-to-char' instruction.
2234 locations->SetInAt(0, Location::RequiresRegister());
2235 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2236 break;
2237
2238 default:
2239 LOG(FATAL) << "Unexpected type conversion from " << input_type
2240 << " to " << result_type;
2241 }
2242 break;
2243
Roland Levillaindff1f282014-11-05 14:15:05 +00002244 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002245 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002246 case Primitive::kPrimBoolean:
2247 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002248 case Primitive::kPrimByte:
2249 case Primitive::kPrimShort:
2250 case Primitive::kPrimInt:
2251 case Primitive::kPrimChar:
2252 // Processing a Dex `int-to-float' instruction.
2253 locations->SetInAt(0, Location::RequiresRegister());
2254 locations->SetOut(Location::RequiresFpuRegister());
2255 break;
2256
Roland Levillain5b3ee562015-04-14 16:02:41 +01002257 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002258 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002259 InvokeRuntimeCallingConvention calling_convention;
2260 locations->SetInAt(0, Location::RegisterPairLocation(
2261 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2262 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002263 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002264 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002265
Roland Levillaincff13742014-11-17 14:32:17 +00002266 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002267 // Processing a Dex `double-to-float' instruction.
2268 locations->SetInAt(0, Location::RequiresFpuRegister());
2269 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002270 break;
2271
2272 default:
2273 LOG(FATAL) << "Unexpected type conversion from " << input_type
2274 << " to " << result_type;
2275 };
2276 break;
2277
Roland Levillaindff1f282014-11-05 14:15:05 +00002278 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002279 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002280 case Primitive::kPrimBoolean:
2281 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002282 case Primitive::kPrimByte:
2283 case Primitive::kPrimShort:
2284 case Primitive::kPrimInt:
2285 case Primitive::kPrimChar:
2286 // Processing a Dex `int-to-double' instruction.
2287 locations->SetInAt(0, Location::RequiresRegister());
2288 locations->SetOut(Location::RequiresFpuRegister());
2289 break;
2290
2291 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002292 // Processing a Dex `long-to-double' instruction.
2293 locations->SetInAt(0, Location::RequiresRegister());
2294 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002295 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002296 locations->AddTemp(Location::RequiresFpuRegister());
2297 break;
2298
Roland Levillaincff13742014-11-17 14:32:17 +00002299 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002300 // Processing a Dex `float-to-double' instruction.
2301 locations->SetInAt(0, Location::RequiresFpuRegister());
2302 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002303 break;
2304
2305 default:
2306 LOG(FATAL) << "Unexpected type conversion from " << input_type
2307 << " to " << result_type;
2308 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002309 break;
2310
2311 default:
2312 LOG(FATAL) << "Unexpected type conversion from " << input_type
2313 << " to " << result_type;
2314 }
2315}
2316
2317void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2318 LocationSummary* locations = conversion->GetLocations();
2319 Location out = locations->Out();
2320 Location in = locations->InAt(0);
2321 Primitive::Type result_type = conversion->GetResultType();
2322 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002323 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002324 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002325 case Primitive::kPrimByte:
2326 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002327 case Primitive::kPrimBoolean:
2328 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002329 case Primitive::kPrimShort:
2330 case Primitive::kPrimInt:
2331 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002332 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002333 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002334 break;
2335
2336 default:
2337 LOG(FATAL) << "Unexpected type conversion from " << input_type
2338 << " to " << result_type;
2339 }
2340 break;
2341
Roland Levillain01a8d712014-11-14 16:27:39 +00002342 case Primitive::kPrimShort:
2343 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002344 case Primitive::kPrimBoolean:
2345 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002346 case Primitive::kPrimByte:
2347 case Primitive::kPrimInt:
2348 case Primitive::kPrimChar:
2349 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002350 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002351 break;
2352
2353 default:
2354 LOG(FATAL) << "Unexpected type conversion from " << input_type
2355 << " to " << result_type;
2356 }
2357 break;
2358
Roland Levillain946e1432014-11-11 17:35:19 +00002359 case Primitive::kPrimInt:
2360 switch (input_type) {
2361 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002362 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002363 DCHECK(out.IsRegister());
2364 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002365 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002366 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002367 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002368 } else {
2369 DCHECK(in.IsConstant());
2370 DCHECK(in.GetConstant()->IsLongConstant());
2371 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002372 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002373 }
2374 break;
2375
Roland Levillain3f8f9362014-12-02 17:45:01 +00002376 case Primitive::kPrimFloat: {
2377 // Processing a Dex `float-to-int' instruction.
2378 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2379 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2380 __ vcvtis(temp, temp);
2381 __ vmovrs(out.AsRegister<Register>(), temp);
2382 break;
2383 }
2384
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002385 case Primitive::kPrimDouble: {
2386 // Processing a Dex `double-to-int' instruction.
2387 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2388 DRegister temp_d = FromLowSToD(temp_s);
2389 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2390 __ vcvtid(temp_s, temp_d);
2391 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002392 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002393 }
Roland Levillain946e1432014-11-11 17:35:19 +00002394
2395 default:
2396 LOG(FATAL) << "Unexpected type conversion from " << input_type
2397 << " to " << result_type;
2398 }
2399 break;
2400
Roland Levillaindff1f282014-11-05 14:15:05 +00002401 case Primitive::kPrimLong:
2402 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002403 case Primitive::kPrimBoolean:
2404 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002405 case Primitive::kPrimByte:
2406 case Primitive::kPrimShort:
2407 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002408 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002409 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002410 DCHECK(out.IsRegisterPair());
2411 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002412 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002413 // Sign extension.
2414 __ Asr(out.AsRegisterPairHigh<Register>(),
2415 out.AsRegisterPairLow<Register>(),
2416 31);
2417 break;
2418
2419 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002420 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002421 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2422 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002423 conversion->GetDexPc(),
2424 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002425 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002426 break;
2427
Roland Levillaindff1f282014-11-05 14:15:05 +00002428 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002429 // Processing a Dex `double-to-long' instruction.
2430 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2431 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002432 conversion->GetDexPc(),
2433 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002434 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002435 break;
2436
2437 default:
2438 LOG(FATAL) << "Unexpected type conversion from " << input_type
2439 << " to " << result_type;
2440 }
2441 break;
2442
Roland Levillain981e4542014-11-14 11:47:14 +00002443 case Primitive::kPrimChar:
2444 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002445 case Primitive::kPrimBoolean:
2446 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002447 case Primitive::kPrimByte:
2448 case Primitive::kPrimShort:
2449 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002450 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002451 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002452 break;
2453
2454 default:
2455 LOG(FATAL) << "Unexpected type conversion from " << input_type
2456 << " to " << result_type;
2457 }
2458 break;
2459
Roland Levillaindff1f282014-11-05 14:15:05 +00002460 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002461 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002462 case Primitive::kPrimBoolean:
2463 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002464 case Primitive::kPrimByte:
2465 case Primitive::kPrimShort:
2466 case Primitive::kPrimInt:
2467 case Primitive::kPrimChar: {
2468 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002469 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2470 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002471 break;
2472 }
2473
Roland Levillain5b3ee562015-04-14 16:02:41 +01002474 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002475 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002476 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2477 conversion,
2478 conversion->GetDexPc(),
2479 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002480 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002481 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002482
Roland Levillaincff13742014-11-17 14:32:17 +00002483 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002484 // Processing a Dex `double-to-float' instruction.
2485 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2486 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002487 break;
2488
2489 default:
2490 LOG(FATAL) << "Unexpected type conversion from " << input_type
2491 << " to " << result_type;
2492 };
2493 break;
2494
Roland Levillaindff1f282014-11-05 14:15:05 +00002495 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002496 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002497 case Primitive::kPrimBoolean:
2498 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002499 case Primitive::kPrimByte:
2500 case Primitive::kPrimShort:
2501 case Primitive::kPrimInt:
2502 case Primitive::kPrimChar: {
2503 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002504 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002505 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2506 out.AsFpuRegisterPairLow<SRegister>());
2507 break;
2508 }
2509
Roland Levillain647b9ed2014-11-27 12:06:00 +00002510 case Primitive::kPrimLong: {
2511 // Processing a Dex `long-to-double' instruction.
2512 Register low = in.AsRegisterPairLow<Register>();
2513 Register high = in.AsRegisterPairHigh<Register>();
2514 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2515 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002516 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002517 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002518 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2519 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002520
Roland Levillain682393c2015-04-14 15:57:52 +01002521 // temp_d = int-to-double(high)
2522 __ vmovsr(temp_s, high);
2523 __ vcvtdi(temp_d, temp_s);
2524 // constant_d = k2Pow32EncodingForDouble
2525 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2526 // out_d = unsigned-to-double(low)
2527 __ vmovsr(out_s, low);
2528 __ vcvtdu(out_d, out_s);
2529 // out_d += temp_d * constant_d
2530 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002531 break;
2532 }
2533
Roland Levillaincff13742014-11-17 14:32:17 +00002534 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002535 // Processing a Dex `float-to-double' instruction.
2536 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2537 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002538 break;
2539
2540 default:
2541 LOG(FATAL) << "Unexpected type conversion from " << input_type
2542 << " to " << result_type;
2543 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002544 break;
2545
2546 default:
2547 LOG(FATAL) << "Unexpected type conversion from " << input_type
2548 << " to " << result_type;
2549 }
2550}
2551
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002552void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002553 LocationSummary* locations =
2554 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002555 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002556 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002557 locations->SetInAt(0, Location::RequiresRegister());
2558 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002559 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2560 break;
2561 }
2562
2563 case Primitive::kPrimLong: {
2564 locations->SetInAt(0, Location::RequiresRegister());
2565 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002566 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002567 break;
2568 }
2569
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002570 case Primitive::kPrimFloat:
2571 case Primitive::kPrimDouble: {
2572 locations->SetInAt(0, Location::RequiresFpuRegister());
2573 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002574 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002575 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002576 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002577
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002578 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002579 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002580 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002581}
2582
2583void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2584 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002585 Location out = locations->Out();
2586 Location first = locations->InAt(0);
2587 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002588 switch (add->GetResultType()) {
2589 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002590 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002591 __ add(out.AsRegister<Register>(),
2592 first.AsRegister<Register>(),
2593 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002594 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002595 __ AddConstant(out.AsRegister<Register>(),
2596 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002597 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002598 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002599 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002600
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002601 case Primitive::kPrimLong: {
2602 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002603 __ adds(out.AsRegisterPairLow<Register>(),
2604 first.AsRegisterPairLow<Register>(),
2605 ShifterOperand(second.AsRegisterPairLow<Register>()));
2606 __ adc(out.AsRegisterPairHigh<Register>(),
2607 first.AsRegisterPairHigh<Register>(),
2608 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002609 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002610 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002611
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002612 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002613 __ vadds(out.AsFpuRegister<SRegister>(),
2614 first.AsFpuRegister<SRegister>(),
2615 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002616 break;
2617
2618 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002619 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2620 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2621 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002622 break;
2623
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002624 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002625 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002626 }
2627}
2628
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002629void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002630 LocationSummary* locations =
2631 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002632 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002633 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002634 locations->SetInAt(0, Location::RequiresRegister());
2635 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002636 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2637 break;
2638 }
2639
2640 case Primitive::kPrimLong: {
2641 locations->SetInAt(0, Location::RequiresRegister());
2642 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002643 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002644 break;
2645 }
Calin Juravle11351682014-10-23 15:38:15 +01002646 case Primitive::kPrimFloat:
2647 case Primitive::kPrimDouble: {
2648 locations->SetInAt(0, Location::RequiresFpuRegister());
2649 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002650 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002651 break;
Calin Juravle11351682014-10-23 15:38:15 +01002652 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002653 default:
Calin Juravle11351682014-10-23 15:38:15 +01002654 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002655 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002656}
2657
2658void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2659 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002660 Location out = locations->Out();
2661 Location first = locations->InAt(0);
2662 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002663 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002664 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002665 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002666 __ sub(out.AsRegister<Register>(),
2667 first.AsRegister<Register>(),
2668 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002669 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002670 __ AddConstant(out.AsRegister<Register>(),
2671 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002672 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002673 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002674 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002675 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002676
Calin Juravle11351682014-10-23 15:38:15 +01002677 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002678 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002679 __ subs(out.AsRegisterPairLow<Register>(),
2680 first.AsRegisterPairLow<Register>(),
2681 ShifterOperand(second.AsRegisterPairLow<Register>()));
2682 __ sbc(out.AsRegisterPairHigh<Register>(),
2683 first.AsRegisterPairHigh<Register>(),
2684 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002685 break;
Calin Juravle11351682014-10-23 15:38:15 +01002686 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002687
Calin Juravle11351682014-10-23 15:38:15 +01002688 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002689 __ vsubs(out.AsFpuRegister<SRegister>(),
2690 first.AsFpuRegister<SRegister>(),
2691 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002692 break;
Calin Juravle11351682014-10-23 15:38:15 +01002693 }
2694
2695 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002696 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2697 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2698 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002699 break;
2700 }
2701
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002702
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002703 default:
Calin Juravle11351682014-10-23 15:38:15 +01002704 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002705 }
2706}
2707
Calin Juravle34bacdf2014-10-07 20:23:36 +01002708void LocationsBuilderARM::VisitMul(HMul* mul) {
2709 LocationSummary* locations =
2710 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2711 switch (mul->GetResultType()) {
2712 case Primitive::kPrimInt:
2713 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002714 locations->SetInAt(0, Location::RequiresRegister());
2715 locations->SetInAt(1, Location::RequiresRegister());
2716 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002717 break;
2718 }
2719
Calin Juravleb5bfa962014-10-21 18:02:24 +01002720 case Primitive::kPrimFloat:
2721 case Primitive::kPrimDouble: {
2722 locations->SetInAt(0, Location::RequiresFpuRegister());
2723 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002724 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002725 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002726 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002727
2728 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002729 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002730 }
2731}
2732
2733void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2734 LocationSummary* locations = mul->GetLocations();
2735 Location out = locations->Out();
2736 Location first = locations->InAt(0);
2737 Location second = locations->InAt(1);
2738 switch (mul->GetResultType()) {
2739 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002740 __ mul(out.AsRegister<Register>(),
2741 first.AsRegister<Register>(),
2742 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002743 break;
2744 }
2745 case Primitive::kPrimLong: {
2746 Register out_hi = out.AsRegisterPairHigh<Register>();
2747 Register out_lo = out.AsRegisterPairLow<Register>();
2748 Register in1_hi = first.AsRegisterPairHigh<Register>();
2749 Register in1_lo = first.AsRegisterPairLow<Register>();
2750 Register in2_hi = second.AsRegisterPairHigh<Register>();
2751 Register in2_lo = second.AsRegisterPairLow<Register>();
2752
2753 // Extra checks to protect caused by the existence of R1_R2.
2754 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2755 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2756 DCHECK_NE(out_hi, in1_lo);
2757 DCHECK_NE(out_hi, in2_lo);
2758
2759 // input: in1 - 64 bits, in2 - 64 bits
2760 // output: out
2761 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2762 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2763 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2764
2765 // IP <- in1.lo * in2.hi
2766 __ mul(IP, in1_lo, in2_hi);
2767 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2768 __ mla(out_hi, in1_hi, in2_lo, IP);
2769 // out.lo <- (in1.lo * in2.lo)[31:0];
2770 __ umull(out_lo, IP, in1_lo, in2_lo);
2771 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2772 __ add(out_hi, out_hi, ShifterOperand(IP));
2773 break;
2774 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002775
2776 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002777 __ vmuls(out.AsFpuRegister<SRegister>(),
2778 first.AsFpuRegister<SRegister>(),
2779 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002780 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002781 }
2782
2783 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002784 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2785 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2786 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002787 break;
2788 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002789
2790 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002791 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002792 }
2793}
2794
Zheng Xuc6667102015-05-15 16:08:45 +08002795void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2796 DCHECK(instruction->IsDiv() || instruction->IsRem());
2797 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2798
2799 LocationSummary* locations = instruction->GetLocations();
2800 Location second = locations->InAt(1);
2801 DCHECK(second.IsConstant());
2802
2803 Register out = locations->Out().AsRegister<Register>();
2804 Register dividend = locations->InAt(0).AsRegister<Register>();
2805 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2806 DCHECK(imm == 1 || imm == -1);
2807
2808 if (instruction->IsRem()) {
2809 __ LoadImmediate(out, 0);
2810 } else {
2811 if (imm == 1) {
2812 __ Mov(out, dividend);
2813 } else {
2814 __ rsb(out, dividend, ShifterOperand(0));
2815 }
2816 }
2817}
2818
2819void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2820 DCHECK(instruction->IsDiv() || instruction->IsRem());
2821 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2822
2823 LocationSummary* locations = instruction->GetLocations();
2824 Location second = locations->InAt(1);
2825 DCHECK(second.IsConstant());
2826
2827 Register out = locations->Out().AsRegister<Register>();
2828 Register dividend = locations->InAt(0).AsRegister<Register>();
2829 Register temp = locations->GetTemp(0).AsRegister<Register>();
2830 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002831 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002832 DCHECK(IsPowerOfTwo(abs_imm));
2833 int ctz_imm = CTZ(abs_imm);
2834
2835 if (ctz_imm == 1) {
2836 __ Lsr(temp, dividend, 32 - ctz_imm);
2837 } else {
2838 __ Asr(temp, dividend, 31);
2839 __ Lsr(temp, temp, 32 - ctz_imm);
2840 }
2841 __ add(out, temp, ShifterOperand(dividend));
2842
2843 if (instruction->IsDiv()) {
2844 __ Asr(out, out, ctz_imm);
2845 if (imm < 0) {
2846 __ rsb(out, out, ShifterOperand(0));
2847 }
2848 } else {
2849 __ ubfx(out, out, 0, ctz_imm);
2850 __ sub(out, out, ShifterOperand(temp));
2851 }
2852}
2853
2854void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2855 DCHECK(instruction->IsDiv() || instruction->IsRem());
2856 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2857
2858 LocationSummary* locations = instruction->GetLocations();
2859 Location second = locations->InAt(1);
2860 DCHECK(second.IsConstant());
2861
2862 Register out = locations->Out().AsRegister<Register>();
2863 Register dividend = locations->InAt(0).AsRegister<Register>();
2864 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2865 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2866 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2867
2868 int64_t magic;
2869 int shift;
2870 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2871
2872 __ LoadImmediate(temp1, magic);
2873 __ smull(temp2, temp1, dividend, temp1);
2874
2875 if (imm > 0 && magic < 0) {
2876 __ add(temp1, temp1, ShifterOperand(dividend));
2877 } else if (imm < 0 && magic > 0) {
2878 __ sub(temp1, temp1, ShifterOperand(dividend));
2879 }
2880
2881 if (shift != 0) {
2882 __ Asr(temp1, temp1, shift);
2883 }
2884
2885 if (instruction->IsDiv()) {
2886 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2887 } else {
2888 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2889 // TODO: Strength reduction for mls.
2890 __ LoadImmediate(temp2, imm);
2891 __ mls(out, temp1, temp2, dividend);
2892 }
2893}
2894
2895void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2896 DCHECK(instruction->IsDiv() || instruction->IsRem());
2897 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2898
2899 LocationSummary* locations = instruction->GetLocations();
2900 Location second = locations->InAt(1);
2901 DCHECK(second.IsConstant());
2902
2903 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2904 if (imm == 0) {
2905 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2906 } else if (imm == 1 || imm == -1) {
2907 DivRemOneOrMinusOne(instruction);
2908 } else if (IsPowerOfTwo(std::abs(imm))) {
2909 DivRemByPowerOfTwo(instruction);
2910 } else {
2911 DCHECK(imm <= -2 || imm >= 2);
2912 GenerateDivRemWithAnyConstant(instruction);
2913 }
2914}
2915
Calin Juravle7c4954d2014-10-28 16:57:40 +00002916void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002917 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2918 if (div->GetResultType() == Primitive::kPrimLong) {
2919 // pLdiv runtime call.
2920 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002921 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2922 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002923 } else if (div->GetResultType() == Primitive::kPrimInt &&
2924 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2925 // pIdivmod runtime call.
2926 call_kind = LocationSummary::kCall;
2927 }
2928
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002929 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2930
Calin Juravle7c4954d2014-10-28 16:57:40 +00002931 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002932 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002933 if (div->InputAt(1)->IsConstant()) {
2934 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002935 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002936 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2937 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2938 if (abs_imm <= 1) {
2939 // No temp register required.
2940 } else {
2941 locations->AddTemp(Location::RequiresRegister());
2942 if (!IsPowerOfTwo(abs_imm)) {
2943 locations->AddTemp(Location::RequiresRegister());
2944 }
2945 }
2946 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002947 locations->SetInAt(0, Location::RequiresRegister());
2948 locations->SetInAt(1, Location::RequiresRegister());
2949 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2950 } else {
2951 InvokeRuntimeCallingConvention calling_convention;
2952 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2953 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2954 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2955 // we only need the former.
2956 locations->SetOut(Location::RegisterLocation(R0));
2957 }
Calin Juravled0d48522014-11-04 16:40:20 +00002958 break;
2959 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002960 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002961 InvokeRuntimeCallingConvention calling_convention;
2962 locations->SetInAt(0, Location::RegisterPairLocation(
2963 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2964 locations->SetInAt(1, Location::RegisterPairLocation(
2965 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002966 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002967 break;
2968 }
2969 case Primitive::kPrimFloat:
2970 case Primitive::kPrimDouble: {
2971 locations->SetInAt(0, Location::RequiresFpuRegister());
2972 locations->SetInAt(1, Location::RequiresFpuRegister());
2973 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2974 break;
2975 }
2976
2977 default:
2978 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2979 }
2980}
2981
2982void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2983 LocationSummary* locations = div->GetLocations();
2984 Location out = locations->Out();
2985 Location first = locations->InAt(0);
2986 Location second = locations->InAt(1);
2987
2988 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002989 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002990 if (second.IsConstant()) {
2991 GenerateDivRemConstantIntegral(div);
2992 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002993 __ sdiv(out.AsRegister<Register>(),
2994 first.AsRegister<Register>(),
2995 second.AsRegister<Register>());
2996 } else {
2997 InvokeRuntimeCallingConvention calling_convention;
2998 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2999 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3000 DCHECK_EQ(R0, out.AsRegister<Register>());
3001
3002 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003003 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003004 }
Calin Juravled0d48522014-11-04 16:40:20 +00003005 break;
3006 }
3007
Calin Juravle7c4954d2014-10-28 16:57:40 +00003008 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003009 InvokeRuntimeCallingConvention calling_convention;
3010 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3011 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3012 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3013 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3014 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003015 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003016
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003017 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003018 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00003019 break;
3020 }
3021
3022 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003023 __ vdivs(out.AsFpuRegister<SRegister>(),
3024 first.AsFpuRegister<SRegister>(),
3025 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003026 break;
3027 }
3028
3029 case Primitive::kPrimDouble: {
3030 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3031 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3032 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3033 break;
3034 }
3035
3036 default:
3037 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3038 }
3039}
3040
Calin Juravlebacfec32014-11-14 15:54:36 +00003041void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003042 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003043
3044 // Most remainders are implemented in the runtime.
3045 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08003046 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3047 // sdiv will be replaced by other instruction sequence.
3048 call_kind = LocationSummary::kNoCall;
3049 } else if ((rem->GetResultType() == Primitive::kPrimInt)
3050 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003051 // Have hardware divide instruction for int, do it with three instructions.
3052 call_kind = LocationSummary::kNoCall;
3053 }
3054
Calin Juravlebacfec32014-11-14 15:54:36 +00003055 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3056
Calin Juravled2ec87d2014-12-08 14:24:46 +00003057 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003058 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003059 if (rem->InputAt(1)->IsConstant()) {
3060 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003061 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003062 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3063 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
3064 if (abs_imm <= 1) {
3065 // No temp register required.
3066 } else {
3067 locations->AddTemp(Location::RequiresRegister());
3068 if (!IsPowerOfTwo(abs_imm)) {
3069 locations->AddTemp(Location::RequiresRegister());
3070 }
3071 }
3072 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003073 locations->SetInAt(0, Location::RequiresRegister());
3074 locations->SetInAt(1, Location::RequiresRegister());
3075 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3076 locations->AddTemp(Location::RequiresRegister());
3077 } else {
3078 InvokeRuntimeCallingConvention calling_convention;
3079 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3080 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3081 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3082 // we only need the latter.
3083 locations->SetOut(Location::RegisterLocation(R1));
3084 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003085 break;
3086 }
3087 case Primitive::kPrimLong: {
3088 InvokeRuntimeCallingConvention calling_convention;
3089 locations->SetInAt(0, Location::RegisterPairLocation(
3090 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3091 locations->SetInAt(1, Location::RegisterPairLocation(
3092 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3093 // The runtime helper puts the output in R2,R3.
3094 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3095 break;
3096 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003097 case Primitive::kPrimFloat: {
3098 InvokeRuntimeCallingConvention calling_convention;
3099 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3100 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3101 locations->SetOut(Location::FpuRegisterLocation(S0));
3102 break;
3103 }
3104
Calin Juravlebacfec32014-11-14 15:54:36 +00003105 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003106 InvokeRuntimeCallingConvention calling_convention;
3107 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3108 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3109 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3110 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3111 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003112 break;
3113 }
3114
3115 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003116 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003117 }
3118}
3119
3120void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3121 LocationSummary* locations = rem->GetLocations();
3122 Location out = locations->Out();
3123 Location first = locations->InAt(0);
3124 Location second = locations->InAt(1);
3125
Calin Juravled2ec87d2014-12-08 14:24:46 +00003126 Primitive::Type type = rem->GetResultType();
3127 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003128 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003129 if (second.IsConstant()) {
3130 GenerateDivRemConstantIntegral(rem);
3131 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003132 Register reg1 = first.AsRegister<Register>();
3133 Register reg2 = second.AsRegister<Register>();
3134 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003135
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003136 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003137 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003138 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003139 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003140 } else {
3141 InvokeRuntimeCallingConvention calling_convention;
3142 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3143 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3144 DCHECK_EQ(R1, out.AsRegister<Register>());
3145
3146 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003147 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003148 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003149 break;
3150 }
3151
3152 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003153 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003154 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003155 break;
3156 }
3157
Calin Juravled2ec87d2014-12-08 14:24:46 +00003158 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003159 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003160 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003161 break;
3162 }
3163
Calin Juravlebacfec32014-11-14 15:54:36 +00003164 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003165 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003166 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003167 break;
3168 }
3169
3170 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003171 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003172 }
3173}
3174
Calin Juravled0d48522014-11-04 16:40:20 +00003175void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003176 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3177 ? LocationSummary::kCallOnSlowPath
3178 : LocationSummary::kNoCall;
3179 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003180 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003181 if (instruction->HasUses()) {
3182 locations->SetOut(Location::SameAsFirstInput());
3183 }
3184}
3185
3186void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003187 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003188 codegen_->AddSlowPath(slow_path);
3189
3190 LocationSummary* locations = instruction->GetLocations();
3191 Location value = locations->InAt(0);
3192
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003193 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003194 case Primitive::kPrimByte:
3195 case Primitive::kPrimChar:
3196 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003197 case Primitive::kPrimInt: {
3198 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003199 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003200 } else {
3201 DCHECK(value.IsConstant()) << value;
3202 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3203 __ b(slow_path->GetEntryLabel());
3204 }
3205 }
3206 break;
3207 }
3208 case Primitive::kPrimLong: {
3209 if (value.IsRegisterPair()) {
3210 __ orrs(IP,
3211 value.AsRegisterPairLow<Register>(),
3212 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3213 __ b(slow_path->GetEntryLabel(), EQ);
3214 } else {
3215 DCHECK(value.IsConstant()) << value;
3216 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3217 __ b(slow_path->GetEntryLabel());
3218 }
3219 }
3220 break;
3221 default:
3222 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3223 }
3224 }
Calin Juravled0d48522014-11-04 16:40:20 +00003225}
3226
Calin Juravle9aec02f2014-11-18 23:06:35 +00003227void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3228 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3229
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003230 LocationSummary* locations =
3231 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003232
3233 switch (op->GetResultType()) {
3234 case Primitive::kPrimInt: {
3235 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003236 if (op->InputAt(1)->IsConstant()) {
3237 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3238 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3239 } else {
3240 locations->SetInAt(1, Location::RequiresRegister());
3241 // Make the output overlap, as it will be used to hold the masked
3242 // second input.
3243 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3244 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003245 break;
3246 }
3247 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003248 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003249 if (op->InputAt(1)->IsConstant()) {
3250 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3251 // For simplicity, use kOutputOverlap even though we only require that low registers
3252 // don't clash with high registers which the register allocator currently guarantees.
3253 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3254 } else {
3255 locations->SetInAt(1, Location::RequiresRegister());
3256 locations->AddTemp(Location::RequiresRegister());
3257 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3258 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003259 break;
3260 }
3261 default:
3262 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3263 }
3264}
3265
3266void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3267 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3268
3269 LocationSummary* locations = op->GetLocations();
3270 Location out = locations->Out();
3271 Location first = locations->InAt(0);
3272 Location second = locations->InAt(1);
3273
3274 Primitive::Type type = op->GetResultType();
3275 switch (type) {
3276 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003277 Register out_reg = out.AsRegister<Register>();
3278 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003279 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003280 Register second_reg = second.AsRegister<Register>();
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003281 // Arm doesn't mask the shift count so we need to do it ourselves.
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003282 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003283 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003284 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003285 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003286 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003287 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003288 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003289 }
3290 } else {
3291 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3292 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
3293 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
3294 __ Mov(out_reg, first_reg);
3295 } else if (op->IsShl()) {
3296 __ Lsl(out_reg, first_reg, shift_value);
3297 } else if (op->IsShr()) {
3298 __ Asr(out_reg, first_reg, shift_value);
3299 } else {
3300 __ Lsr(out_reg, first_reg, shift_value);
3301 }
3302 }
3303 break;
3304 }
3305 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003306 Register o_h = out.AsRegisterPairHigh<Register>();
3307 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003308
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003309 Register high = first.AsRegisterPairHigh<Register>();
3310 Register low = first.AsRegisterPairLow<Register>();
3311
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003312 if (second.IsRegister()) {
3313 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003314
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003315 Register second_reg = second.AsRegister<Register>();
3316
3317 if (op->IsShl()) {
3318 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
3319 // Shift the high part
3320 __ Lsl(o_h, high, o_l);
3321 // Shift the low part and `or` what overflew on the high part
3322 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3323 __ Lsr(temp, low, temp);
3324 __ orr(o_h, o_h, ShifterOperand(temp));
3325 // If the shift is > 32 bits, override the high part
3326 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3327 __ it(PL);
3328 __ Lsl(o_h, low, temp, PL);
3329 // Shift the low part
3330 __ Lsl(o_l, low, o_l);
3331 } else if (op->IsShr()) {
3332 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3333 // Shift the low part
3334 __ Lsr(o_l, low, o_h);
3335 // Shift the high part and `or` what underflew on the low part
3336 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3337 __ Lsl(temp, high, temp);
3338 __ orr(o_l, o_l, ShifterOperand(temp));
3339 // If the shift is > 32 bits, override the low part
3340 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3341 __ it(PL);
3342 __ Asr(o_l, high, temp, PL);
3343 // Shift the high part
3344 __ Asr(o_h, high, o_h);
3345 } else {
3346 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3347 // same as Shr except we use `Lsr`s and not `Asr`s
3348 __ Lsr(o_l, low, o_h);
3349 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3350 __ Lsl(temp, high, temp);
3351 __ orr(o_l, o_l, ShifterOperand(temp));
3352 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3353 __ it(PL);
3354 __ Lsr(o_l, high, temp, PL);
3355 __ Lsr(o_h, high, o_h);
3356 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003357 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003358 // Register allocator doesn't create partial overlap.
3359 DCHECK_NE(o_l, high);
3360 DCHECK_NE(o_h, low);
3361 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3362 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxLongShiftValue);
3363 if (shift_value > 32) {
3364 if (op->IsShl()) {
3365 __ Lsl(o_h, low, shift_value - 32);
3366 __ LoadImmediate(o_l, 0);
3367 } else if (op->IsShr()) {
3368 __ Asr(o_l, high, shift_value - 32);
3369 __ Asr(o_h, high, 31);
3370 } else {
3371 __ Lsr(o_l, high, shift_value - 32);
3372 __ LoadImmediate(o_h, 0);
3373 }
3374 } else if (shift_value == 32) {
3375 if (op->IsShl()) {
3376 __ mov(o_h, ShifterOperand(low));
3377 __ LoadImmediate(o_l, 0);
3378 } else if (op->IsShr()) {
3379 __ mov(o_l, ShifterOperand(high));
3380 __ Asr(o_h, high, 31);
3381 } else {
3382 __ mov(o_l, ShifterOperand(high));
3383 __ LoadImmediate(o_h, 0);
3384 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003385 } else if (shift_value == 1) {
3386 if (op->IsShl()) {
3387 __ Lsls(o_l, low, 1);
3388 __ adc(o_h, high, ShifterOperand(high));
3389 } else if (op->IsShr()) {
3390 __ Asrs(o_h, high, 1);
3391 __ Rrx(o_l, low);
3392 } else {
3393 __ Lsrs(o_h, high, 1);
3394 __ Rrx(o_l, low);
3395 }
3396 } else {
3397 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003398 if (op->IsShl()) {
3399 __ Lsl(o_h, high, shift_value);
3400 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3401 __ Lsl(o_l, low, shift_value);
3402 } else if (op->IsShr()) {
3403 __ Lsr(o_l, low, shift_value);
3404 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3405 __ Asr(o_h, high, shift_value);
3406 } else {
3407 __ Lsr(o_l, low, shift_value);
3408 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3409 __ Lsr(o_h, high, shift_value);
3410 }
3411 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003412 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003413 break;
3414 }
3415 default:
3416 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003417 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003418 }
3419}
3420
3421void LocationsBuilderARM::VisitShl(HShl* shl) {
3422 HandleShift(shl);
3423}
3424
3425void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3426 HandleShift(shl);
3427}
3428
3429void LocationsBuilderARM::VisitShr(HShr* shr) {
3430 HandleShift(shr);
3431}
3432
3433void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3434 HandleShift(shr);
3435}
3436
3437void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3438 HandleShift(ushr);
3439}
3440
3441void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3442 HandleShift(ushr);
3443}
3444
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003445void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003446 LocationSummary* locations =
3447 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003448 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray729645a2015-11-19 13:29:02 +00003449 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3450 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003451 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003452}
3453
3454void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003455 // Note: if heap poisoning is enabled, the entry point takes cares
3456 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003457 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003458 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003459 instruction->GetDexPc(),
3460 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003461 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003462}
3463
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003464void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3465 LocationSummary* locations =
3466 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3467 InvokeRuntimeCallingConvention calling_convention;
3468 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003469 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003470 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003471 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003472}
3473
3474void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3475 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003476 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003477 // Note: if heap poisoning is enabled, the entry point takes cares
3478 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003479 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003480 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003481 instruction->GetDexPc(),
3482 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003483 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003484}
3485
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003486void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003487 LocationSummary* locations =
3488 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003489 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3490 if (location.IsStackSlot()) {
3491 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3492 } else if (location.IsDoubleStackSlot()) {
3493 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003494 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003495 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003496}
3497
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003498void InstructionCodeGeneratorARM::VisitParameterValue(
3499 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003500 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003501}
3502
3503void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3504 LocationSummary* locations =
3505 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3506 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3507}
3508
3509void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3510 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003511}
3512
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003513void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003514 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003515 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003516 locations->SetInAt(0, Location::RequiresRegister());
3517 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003518}
3519
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003520void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3521 LocationSummary* locations = not_->GetLocations();
3522 Location out = locations->Out();
3523 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003524 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003525 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003526 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003527 break;
3528
3529 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003530 __ mvn(out.AsRegisterPairLow<Register>(),
3531 ShifterOperand(in.AsRegisterPairLow<Register>()));
3532 __ mvn(out.AsRegisterPairHigh<Register>(),
3533 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003534 break;
3535
3536 default:
3537 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3538 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003539}
3540
David Brazdil66d126e2015-04-03 16:02:44 +01003541void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3542 LocationSummary* locations =
3543 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3544 locations->SetInAt(0, Location::RequiresRegister());
3545 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3546}
3547
3548void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003549 LocationSummary* locations = bool_not->GetLocations();
3550 Location out = locations->Out();
3551 Location in = locations->InAt(0);
3552 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3553}
3554
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003555void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003556 LocationSummary* locations =
3557 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003558 switch (compare->InputAt(0)->GetType()) {
3559 case Primitive::kPrimLong: {
3560 locations->SetInAt(0, Location::RequiresRegister());
3561 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003562 // Output overlaps because it is written before doing the low comparison.
3563 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003564 break;
3565 }
3566 case Primitive::kPrimFloat:
3567 case Primitive::kPrimDouble: {
3568 locations->SetInAt(0, Location::RequiresFpuRegister());
3569 locations->SetInAt(1, Location::RequiresFpuRegister());
3570 locations->SetOut(Location::RequiresRegister());
3571 break;
3572 }
3573 default:
3574 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3575 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003576}
3577
3578void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003579 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003580 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003581 Location left = locations->InAt(0);
3582 Location right = locations->InAt(1);
3583
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003584 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003585 Primitive::Type type = compare->InputAt(0)->GetType();
3586 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003587 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003588 __ cmp(left.AsRegisterPairHigh<Register>(),
3589 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003590 __ b(&less, LT);
3591 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003592 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003593 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003594 __ cmp(left.AsRegisterPairLow<Register>(),
3595 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003596 break;
3597 }
3598 case Primitive::kPrimFloat:
3599 case Primitive::kPrimDouble: {
3600 __ LoadImmediate(out, 0);
3601 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003602 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003603 } else {
3604 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3605 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3606 }
3607 __ vmstat(); // transfer FP status register to ARM APSR.
3608 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003609 break;
3610 }
3611 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003612 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003613 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003614 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003615 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003616
3617 __ Bind(&greater);
3618 __ LoadImmediate(out, 1);
3619 __ b(&done);
3620
3621 __ Bind(&less);
3622 __ LoadImmediate(out, -1);
3623
3624 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003625}
3626
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003627void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003628 LocationSummary* locations =
3629 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003630 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3631 locations->SetInAt(i, Location::Any());
3632 }
3633 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003634}
3635
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003636void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003637 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003638}
3639
Calin Juravle52c48962014-12-16 17:02:57 +00003640void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3641 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003642 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003643 switch (kind) {
3644 case MemBarrierKind::kAnyStore:
3645 case MemBarrierKind::kLoadAny:
3646 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003647 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003648 break;
3649 }
3650 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003651 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003652 break;
3653 }
3654 default:
3655 LOG(FATAL) << "Unexpected memory barrier " << kind;
3656 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003657 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003658}
3659
3660void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3661 uint32_t offset,
3662 Register out_lo,
3663 Register out_hi) {
3664 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003665 // Ensure `out_lo` is different from `addr`, so that loading
3666 // `offset` into `out_lo` does not clutter `addr`.
3667 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003668 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003669 __ add(IP, addr, ShifterOperand(out_lo));
3670 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003671 }
3672 __ ldrexd(out_lo, out_hi, addr);
3673}
3674
3675void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3676 uint32_t offset,
3677 Register value_lo,
3678 Register value_hi,
3679 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003680 Register temp2,
3681 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003682 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003683 if (offset != 0) {
3684 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003685 __ add(IP, addr, ShifterOperand(temp1));
3686 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003687 }
3688 __ Bind(&fail);
3689 // We need a load followed by store. (The address used in a STREX instruction must
3690 // be the same as the address in the most recently executed LDREX instruction.)
3691 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003692 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003693 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003694 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003695}
3696
3697void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3698 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3699
Nicolas Geoffray39468442014-09-02 15:17:15 +01003700 LocationSummary* locations =
3701 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003702 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003703
Calin Juravle52c48962014-12-16 17:02:57 +00003704 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003705 if (Primitive::IsFloatingPointType(field_type)) {
3706 locations->SetInAt(1, Location::RequiresFpuRegister());
3707 } else {
3708 locations->SetInAt(1, Location::RequiresRegister());
3709 }
3710
Calin Juravle52c48962014-12-16 17:02:57 +00003711 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003712 bool generate_volatile = field_info.IsVolatile()
3713 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003714 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003715 bool needs_write_barrier =
3716 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003717 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003718 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003719 if (needs_write_barrier) {
3720 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003721 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003722 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003723 // Arm encoding have some additional constraints for ldrexd/strexd:
3724 // - registers need to be consecutive
3725 // - the first register should be even but not R14.
3726 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3727 // enable Arm encoding.
3728 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3729
3730 locations->AddTemp(Location::RequiresRegister());
3731 locations->AddTemp(Location::RequiresRegister());
3732 if (field_type == Primitive::kPrimDouble) {
3733 // For doubles we need two more registers to copy the value.
3734 locations->AddTemp(Location::RegisterLocation(R2));
3735 locations->AddTemp(Location::RegisterLocation(R3));
3736 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003737 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003738}
3739
Calin Juravle52c48962014-12-16 17:02:57 +00003740void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003741 const FieldInfo& field_info,
3742 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003743 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3744
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003745 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003746 Register base = locations->InAt(0).AsRegister<Register>();
3747 Location value = locations->InAt(1);
3748
3749 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003750 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003751 Primitive::Type field_type = field_info.GetFieldType();
3752 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003753 bool needs_write_barrier =
3754 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003755
3756 if (is_volatile) {
3757 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3758 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003759
3760 switch (field_type) {
3761 case Primitive::kPrimBoolean:
3762 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003763 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003764 break;
3765 }
3766
3767 case Primitive::kPrimShort:
3768 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003769 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003770 break;
3771 }
3772
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003773 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003774 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003775 if (kPoisonHeapReferences && needs_write_barrier) {
3776 // Note that in the case where `value` is a null reference,
3777 // we do not enter this block, as a null reference does not
3778 // need poisoning.
3779 DCHECK_EQ(field_type, Primitive::kPrimNot);
3780 Register temp = locations->GetTemp(0).AsRegister<Register>();
3781 __ Mov(temp, value.AsRegister<Register>());
3782 __ PoisonHeapReference(temp);
3783 __ StoreToOffset(kStoreWord, temp, base, offset);
3784 } else {
3785 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3786 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003787 break;
3788 }
3789
3790 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003791 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003792 GenerateWideAtomicStore(base, offset,
3793 value.AsRegisterPairLow<Register>(),
3794 value.AsRegisterPairHigh<Register>(),
3795 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003796 locations->GetTemp(1).AsRegister<Register>(),
3797 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003798 } else {
3799 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003800 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003801 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003802 break;
3803 }
3804
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003805 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003806 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003807 break;
3808 }
3809
3810 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003811 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003812 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003813 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3814 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3815
3816 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3817
3818 GenerateWideAtomicStore(base, offset,
3819 value_reg_lo,
3820 value_reg_hi,
3821 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003822 locations->GetTemp(3).AsRegister<Register>(),
3823 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003824 } else {
3825 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003826 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003827 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003828 break;
3829 }
3830
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003831 case Primitive::kPrimVoid:
3832 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003833 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003834 }
Calin Juravle52c48962014-12-16 17:02:57 +00003835
Calin Juravle77520bc2015-01-12 18:45:46 +00003836 // Longs and doubles are handled in the switch.
3837 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3838 codegen_->MaybeRecordImplicitNullCheck(instruction);
3839 }
3840
3841 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3842 Register temp = locations->GetTemp(0).AsRegister<Register>();
3843 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003844 codegen_->MarkGCCard(
3845 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003846 }
3847
Calin Juravle52c48962014-12-16 17:02:57 +00003848 if (is_volatile) {
3849 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3850 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003851}
3852
Calin Juravle52c48962014-12-16 17:02:57 +00003853void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3854 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003855
3856 bool object_field_get_with_read_barrier =
3857 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003858 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003859 new (GetGraph()->GetArena()) LocationSummary(instruction,
3860 object_field_get_with_read_barrier ?
3861 LocationSummary::kCallOnSlowPath :
3862 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003863 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003864
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003865 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003866 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003867 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00003868 // The output overlaps in case of volatile long: we don't want the
3869 // code generated by GenerateWideAtomicLoad to overwrite the
3870 // object's location. Likewise, in the case of an object field get
3871 // with read barriers enabled, we do not want the load to overwrite
3872 // the object's location, as we need it to emit the read barrier.
3873 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
3874 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003875
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003876 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3877 locations->SetOut(Location::RequiresFpuRegister());
3878 } else {
3879 locations->SetOut(Location::RequiresRegister(),
3880 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3881 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003882 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003883 // Arm encoding have some additional constraints for ldrexd/strexd:
3884 // - registers need to be consecutive
3885 // - the first register should be even but not R14.
3886 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3887 // enable Arm encoding.
3888 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3889 locations->AddTemp(Location::RequiresRegister());
3890 locations->AddTemp(Location::RequiresRegister());
3891 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003892}
3893
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003894Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3895 Opcode opcode) {
3896 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3897 if (constant->IsConstant() &&
3898 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3899 return Location::ConstantLocation(constant->AsConstant());
3900 }
3901 return Location::RequiresRegister();
3902}
3903
3904bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3905 Opcode opcode) {
3906 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3907 if (Primitive::Is64BitType(input_cst->GetType())) {
3908 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3909 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3910 } else {
3911 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3912 }
3913}
3914
3915bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
3916 ShifterOperand so;
3917 ArmAssembler* assembler = codegen_->GetAssembler();
3918 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
3919 return true;
3920 }
3921 Opcode neg_opcode = kNoOperand;
3922 switch (opcode) {
3923 case AND:
3924 neg_opcode = BIC;
3925 break;
3926 case ORR:
3927 neg_opcode = ORN;
3928 break;
3929 default:
3930 return false;
3931 }
3932 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
3933}
3934
Calin Juravle52c48962014-12-16 17:02:57 +00003935void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3936 const FieldInfo& field_info) {
3937 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003938
Calin Juravle52c48962014-12-16 17:02:57 +00003939 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00003940 Location base_loc = locations->InAt(0);
3941 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00003942 Location out = locations->Out();
3943 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003944 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003945 Primitive::Type field_type = field_info.GetFieldType();
3946 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3947
3948 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003949 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003950 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003951 break;
3952 }
3953
3954 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003955 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003956 break;
3957 }
3958
3959 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003960 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003961 break;
3962 }
3963
3964 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003965 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003966 break;
3967 }
3968
3969 case Primitive::kPrimInt:
3970 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003971 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003972 break;
3973 }
3974
3975 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003976 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003977 GenerateWideAtomicLoad(base, offset,
3978 out.AsRegisterPairLow<Register>(),
3979 out.AsRegisterPairHigh<Register>());
3980 } else {
3981 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3982 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003983 break;
3984 }
3985
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003986 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003987 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003988 break;
3989 }
3990
3991 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003992 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003993 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003994 Register lo = locations->GetTemp(0).AsRegister<Register>();
3995 Register hi = locations->GetTemp(1).AsRegister<Register>();
3996 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003997 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003998 __ vmovdrr(out_reg, lo, hi);
3999 } else {
4000 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004001 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004002 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004003 break;
4004 }
4005
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004006 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004007 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004008 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004009 }
Calin Juravle52c48962014-12-16 17:02:57 +00004010
Calin Juravle77520bc2015-01-12 18:45:46 +00004011 // Doubles are handled in the switch.
4012 if (field_type != Primitive::kPrimDouble) {
4013 codegen_->MaybeRecordImplicitNullCheck(instruction);
4014 }
4015
Calin Juravle52c48962014-12-16 17:02:57 +00004016 if (is_volatile) {
4017 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4018 }
Roland Levillain4d027112015-07-01 15:41:14 +01004019
4020 if (field_type == Primitive::kPrimNot) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004021 codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004022 }
Calin Juravle52c48962014-12-16 17:02:57 +00004023}
4024
4025void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4026 HandleFieldSet(instruction, instruction->GetFieldInfo());
4027}
4028
4029void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004030 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004031}
4032
4033void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4034 HandleFieldGet(instruction, instruction->GetFieldInfo());
4035}
4036
4037void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4038 HandleFieldGet(instruction, instruction->GetFieldInfo());
4039}
4040
4041void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4042 HandleFieldGet(instruction, instruction->GetFieldInfo());
4043}
4044
4045void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4046 HandleFieldGet(instruction, instruction->GetFieldInfo());
4047}
4048
4049void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4050 HandleFieldSet(instruction, instruction->GetFieldInfo());
4051}
4052
4053void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004054 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004055}
4056
Calin Juravlee460d1d2015-09-29 04:52:17 +01004057void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4058 HUnresolvedInstanceFieldGet* instruction) {
4059 FieldAccessCallingConventionARM calling_convention;
4060 codegen_->CreateUnresolvedFieldLocationSummary(
4061 instruction, instruction->GetFieldType(), calling_convention);
4062}
4063
4064void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4065 HUnresolvedInstanceFieldGet* instruction) {
4066 FieldAccessCallingConventionARM calling_convention;
4067 codegen_->GenerateUnresolvedFieldAccess(instruction,
4068 instruction->GetFieldType(),
4069 instruction->GetFieldIndex(),
4070 instruction->GetDexPc(),
4071 calling_convention);
4072}
4073
4074void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4075 HUnresolvedInstanceFieldSet* instruction) {
4076 FieldAccessCallingConventionARM calling_convention;
4077 codegen_->CreateUnresolvedFieldLocationSummary(
4078 instruction, instruction->GetFieldType(), calling_convention);
4079}
4080
4081void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4082 HUnresolvedInstanceFieldSet* instruction) {
4083 FieldAccessCallingConventionARM calling_convention;
4084 codegen_->GenerateUnresolvedFieldAccess(instruction,
4085 instruction->GetFieldType(),
4086 instruction->GetFieldIndex(),
4087 instruction->GetDexPc(),
4088 calling_convention);
4089}
4090
4091void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4092 HUnresolvedStaticFieldGet* instruction) {
4093 FieldAccessCallingConventionARM calling_convention;
4094 codegen_->CreateUnresolvedFieldLocationSummary(
4095 instruction, instruction->GetFieldType(), calling_convention);
4096}
4097
4098void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4099 HUnresolvedStaticFieldGet* instruction) {
4100 FieldAccessCallingConventionARM calling_convention;
4101 codegen_->GenerateUnresolvedFieldAccess(instruction,
4102 instruction->GetFieldType(),
4103 instruction->GetFieldIndex(),
4104 instruction->GetDexPc(),
4105 calling_convention);
4106}
4107
4108void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4109 HUnresolvedStaticFieldSet* instruction) {
4110 FieldAccessCallingConventionARM calling_convention;
4111 codegen_->CreateUnresolvedFieldLocationSummary(
4112 instruction, instruction->GetFieldType(), calling_convention);
4113}
4114
4115void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4116 HUnresolvedStaticFieldSet* instruction) {
4117 FieldAccessCallingConventionARM calling_convention;
4118 codegen_->GenerateUnresolvedFieldAccess(instruction,
4119 instruction->GetFieldType(),
4120 instruction->GetFieldIndex(),
4121 instruction->GetDexPc(),
4122 calling_convention);
4123}
4124
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004125void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004126 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4127 ? LocationSummary::kCallOnSlowPath
4128 : LocationSummary::kNoCall;
4129 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004130 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004131 if (instruction->HasUses()) {
4132 locations->SetOut(Location::SameAsFirstInput());
4133 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004134}
4135
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004136void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004137 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4138 return;
4139 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004140 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004141
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004142 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4143 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4144}
4145
4146void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004147 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004148 codegen_->AddSlowPath(slow_path);
4149
4150 LocationSummary* locations = instruction->GetLocations();
4151 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004152
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004153 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004154}
4155
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004156void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004157 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004158 GenerateImplicitNullCheck(instruction);
4159 } else {
4160 GenerateExplicitNullCheck(instruction);
4161 }
4162}
4163
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004164void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004165 bool object_array_get_with_read_barrier =
4166 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004167 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004168 new (GetGraph()->GetArena()) LocationSummary(instruction,
4169 object_array_get_with_read_barrier ?
4170 LocationSummary::kCallOnSlowPath :
4171 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004172 locations->SetInAt(0, Location::RequiresRegister());
4173 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004174 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4175 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4176 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004177 // The output overlaps in the case of an object array get with
4178 // read barriers enabled: we do not want the move to overwrite the
4179 // array's location, as we need it to emit the read barrier.
4180 locations->SetOut(
4181 Location::RequiresRegister(),
4182 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004183 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004184}
4185
4186void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4187 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004188 Location obj_loc = locations->InAt(0);
4189 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004190 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004191 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004192
Roland Levillain4d027112015-07-01 15:41:14 +01004193 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004194 case Primitive::kPrimBoolean: {
4195 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004196 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004197 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004198 size_t offset =
4199 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004200 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4201 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004202 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004203 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4204 }
4205 break;
4206 }
4207
4208 case Primitive::kPrimByte: {
4209 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004210 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004211 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004212 size_t offset =
4213 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004214 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4215 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004216 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004217 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4218 }
4219 break;
4220 }
4221
4222 case Primitive::kPrimShort: {
4223 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004224 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004225 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004226 size_t offset =
4227 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004228 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4229 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004230 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004231 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4232 }
4233 break;
4234 }
4235
4236 case Primitive::kPrimChar: {
4237 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004238 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004239 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004240 size_t offset =
4241 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004242 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4243 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004244 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004245 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4246 }
4247 break;
4248 }
4249
4250 case Primitive::kPrimInt:
4251 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00004252 static_assert(
4253 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4254 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004255 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004256 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004257 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004258 size_t offset =
4259 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004260 __ LoadFromOffset(kLoadWord, out, obj, offset);
4261 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004262 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004263 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4264 }
4265 break;
4266 }
4267
4268 case Primitive::kPrimLong: {
4269 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004270 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004271 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004272 size_t offset =
4273 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004274 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004275 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004276 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004277 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004278 }
4279 break;
4280 }
4281
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004282 case Primitive::kPrimFloat: {
4283 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4284 Location out = locations->Out();
4285 DCHECK(out.IsFpuRegister());
4286 if (index.IsConstant()) {
4287 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4288 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4289 } else {
4290 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4291 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4292 }
4293 break;
4294 }
4295
4296 case Primitive::kPrimDouble: {
4297 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4298 Location out = locations->Out();
4299 DCHECK(out.IsFpuRegisterPair());
4300 if (index.IsConstant()) {
4301 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4302 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4303 } else {
4304 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4305 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4306 }
4307 break;
4308 }
4309
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004310 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004311 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004312 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004313 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004314 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004315
4316 if (type == Primitive::kPrimNot) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004317 static_assert(
4318 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4319 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4320 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4321 Location out = locations->Out();
4322 if (index.IsConstant()) {
4323 uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4324 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4325 } else {
4326 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4327 }
Roland Levillain4d027112015-07-01 15:41:14 +01004328 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004329}
4330
4331void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004332 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004333
4334 bool needs_write_barrier =
4335 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004336 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4337 bool object_array_set_with_read_barrier =
4338 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004339
Nicolas Geoffray39468442014-09-02 15:17:15 +01004340 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004341 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004342 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4343 LocationSummary::kCallOnSlowPath :
4344 LocationSummary::kNoCall);
4345
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004346 locations->SetInAt(0, Location::RequiresRegister());
4347 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4348 if (Primitive::IsFloatingPointType(value_type)) {
4349 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004350 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004351 locations->SetInAt(2, Location::RequiresRegister());
4352 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004353 if (needs_write_barrier) {
4354 // Temporary registers for the write barrier.
4355 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004356 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004357 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358}
4359
4360void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4361 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004362 Location array_loc = locations->InAt(0);
4363 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004364 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004365 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004366 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004367 bool needs_write_barrier =
4368 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004369
4370 switch (value_type) {
4371 case Primitive::kPrimBoolean:
4372 case Primitive::kPrimByte: {
4373 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004374 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004375 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004376 size_t offset =
4377 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004378 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004379 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004380 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004381 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4382 }
4383 break;
4384 }
4385
4386 case Primitive::kPrimShort:
4387 case Primitive::kPrimChar: {
4388 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004389 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004390 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004391 size_t offset =
4392 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004393 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004394 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004395 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004396 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4397 }
4398 break;
4399 }
4400
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004401 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004402 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004403 Location value_loc = locations->InAt(2);
4404 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004405 Register source = value;
4406
4407 if (instruction->InputAt(2)->IsNullConstant()) {
4408 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004409 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004410 size_t offset =
4411 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004412 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004413 } else {
4414 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004415 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004416 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004417 }
Roland Levillain3b359c72015-11-17 19:35:12 +00004418 DCHECK(!needs_write_barrier);
4419 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004420 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004421 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004422
4423 DCHECK(needs_write_barrier);
4424 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4425 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4426 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4427 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4428 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4429 Label done;
4430 SlowPathCode* slow_path = nullptr;
4431
Roland Levillain3b359c72015-11-17 19:35:12 +00004432 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004433 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4434 codegen_->AddSlowPath(slow_path);
4435 if (instruction->GetValueCanBeNull()) {
4436 Label non_zero;
4437 __ CompareAndBranchIfNonZero(value, &non_zero);
4438 if (index.IsConstant()) {
4439 size_t offset =
4440 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4441 __ StoreToOffset(kStoreWord, value, array, offset);
4442 } else {
4443 DCHECK(index.IsRegister()) << index;
4444 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4445 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4446 }
4447 codegen_->MaybeRecordImplicitNullCheck(instruction);
4448 __ b(&done);
4449 __ Bind(&non_zero);
4450 }
4451
Roland Levillain3b359c72015-11-17 19:35:12 +00004452 if (kEmitCompilerReadBarrier) {
4453 // When read barriers are enabled, the type checking
4454 // instrumentation requires two read barriers:
4455 //
4456 // __ Mov(temp2, temp1);
4457 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4458 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4459 // codegen_->GenerateReadBarrier(
4460 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4461 //
4462 // // /* HeapReference<Class> */ temp2 = value->klass_
4463 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4464 // codegen_->GenerateReadBarrier(
4465 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4466 //
4467 // __ cmp(temp1, ShifterOperand(temp2));
4468 //
4469 // However, the second read barrier may trash `temp`, as it
4470 // is a temporary register, and as such would not be saved
4471 // along with live registers before calling the runtime (nor
4472 // restored afterwards). So in this case, we bail out and
4473 // delegate the work to the array set slow path.
4474 //
4475 // TODO: Extend the register allocator to support a new
4476 // "(locally) live temp" location so as to avoid always
4477 // going into the slow path when read barriers are enabled.
4478 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004479 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004480 // /* HeapReference<Class> */ temp1 = array->klass_
4481 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4482 codegen_->MaybeRecordImplicitNullCheck(instruction);
4483 __ MaybeUnpoisonHeapReference(temp1);
4484
4485 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4486 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4487 // /* HeapReference<Class> */ temp2 = value->klass_
4488 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4489 // If heap poisoning is enabled, no need to unpoison `temp1`
4490 // nor `temp2`, as we are comparing two poisoned references.
4491 __ cmp(temp1, ShifterOperand(temp2));
4492
4493 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4494 Label do_put;
4495 __ b(&do_put, EQ);
4496 // If heap poisoning is enabled, the `temp1` reference has
4497 // not been unpoisoned yet; unpoison it now.
4498 __ MaybeUnpoisonHeapReference(temp1);
4499
4500 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4501 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4502 // If heap poisoning is enabled, no need to unpoison
4503 // `temp1`, as we are comparing against null below.
4504 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4505 __ Bind(&do_put);
4506 } else {
4507 __ b(slow_path->GetEntryLabel(), NE);
4508 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004509 }
4510 }
4511
4512 if (kPoisonHeapReferences) {
4513 // Note that in the case where `value` is a null reference,
4514 // we do not enter this block, as a null reference does not
4515 // need poisoning.
4516 DCHECK_EQ(value_type, Primitive::kPrimNot);
4517 __ Mov(temp1, value);
4518 __ PoisonHeapReference(temp1);
4519 source = temp1;
4520 }
4521
4522 if (index.IsConstant()) {
4523 size_t offset =
4524 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4525 __ StoreToOffset(kStoreWord, source, array, offset);
4526 } else {
4527 DCHECK(index.IsRegister()) << index;
4528 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4529 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4530 }
4531
Roland Levillain3b359c72015-11-17 19:35:12 +00004532 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004533 codegen_->MaybeRecordImplicitNullCheck(instruction);
4534 }
4535
4536 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4537
4538 if (done.IsLinked()) {
4539 __ Bind(&done);
4540 }
4541
4542 if (slow_path != nullptr) {
4543 __ Bind(slow_path->GetExitLabel());
4544 }
4545
4546 break;
4547 }
4548
4549 case Primitive::kPrimInt: {
4550 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4551 Register value = locations->InAt(2).AsRegister<Register>();
4552 if (index.IsConstant()) {
4553 size_t offset =
4554 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4555 __ StoreToOffset(kStoreWord, value, array, offset);
4556 } else {
4557 DCHECK(index.IsRegister()) << index;
4558 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4559 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4560 }
4561
4562 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004563 break;
4564 }
4565
4566 case Primitive::kPrimLong: {
4567 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004568 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004569 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004570 size_t offset =
4571 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004572 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004573 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004574 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004575 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004576 }
4577 break;
4578 }
4579
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004580 case Primitive::kPrimFloat: {
4581 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4582 Location value = locations->InAt(2);
4583 DCHECK(value.IsFpuRegister());
4584 if (index.IsConstant()) {
4585 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004586 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004587 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004588 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004589 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4590 }
4591 break;
4592 }
4593
4594 case Primitive::kPrimDouble: {
4595 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4596 Location value = locations->InAt(2);
4597 DCHECK(value.IsFpuRegisterPair());
4598 if (index.IsConstant()) {
4599 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004600 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004601 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004602 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004603 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4604 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004605
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004606 break;
4607 }
4608
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004609 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004610 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004611 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004612 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004613
4614 // Ints and objects are handled in the switch.
4615 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4616 codegen_->MaybeRecordImplicitNullCheck(instruction);
4617 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004618}
4619
4620void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004621 LocationSummary* locations =
4622 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004623 locations->SetInAt(0, Location::RequiresRegister());
4624 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004625}
4626
4627void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4628 LocationSummary* locations = instruction->GetLocations();
4629 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004630 Register obj = locations->InAt(0).AsRegister<Register>();
4631 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004632 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004633 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004634}
4635
4636void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004637 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4638 ? LocationSummary::kCallOnSlowPath
4639 : LocationSummary::kNoCall;
4640 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004641 locations->SetInAt(0, Location::RequiresRegister());
4642 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004643 if (instruction->HasUses()) {
4644 locations->SetOut(Location::SameAsFirstInput());
4645 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004646}
4647
4648void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4649 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004650 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004651 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004652 codegen_->AddSlowPath(slow_path);
4653
Roland Levillain271ab9c2014-11-27 15:23:57 +00004654 Register index = locations->InAt(0).AsRegister<Register>();
4655 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004656
4657 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004658 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004659}
4660
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004661void CodeGeneratorARM::MarkGCCard(Register temp,
4662 Register card,
4663 Register object,
4664 Register value,
4665 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004666 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004667 if (can_be_null) {
4668 __ CompareAndBranchIfZero(value, &is_null);
4669 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004670 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4671 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4672 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004673 if (can_be_null) {
4674 __ Bind(&is_null);
4675 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004676}
4677
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004678void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4679 temp->SetLocations(nullptr);
4680}
4681
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004682void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004683 // Nothing to do, this is driven by the code generator.
4684}
4685
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004686void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004687 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004688}
4689
4690void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004691 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4692}
4693
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004694void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4695 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4696}
4697
4698void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004699 HBasicBlock* block = instruction->GetBlock();
4700 if (block->GetLoopInformation() != nullptr) {
4701 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4702 // The back edge will generate the suspend check.
4703 return;
4704 }
4705 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4706 // The goto will generate the suspend check.
4707 return;
4708 }
4709 GenerateSuspendCheck(instruction, nullptr);
4710}
4711
4712void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4713 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004714 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004715 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4716 if (slow_path == nullptr) {
4717 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4718 instruction->SetSlowPath(slow_path);
4719 codegen_->AddSlowPath(slow_path);
4720 if (successor != nullptr) {
4721 DCHECK(successor->IsLoopHeader());
4722 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4723 }
4724 } else {
4725 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4726 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004727
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004728 __ LoadFromOffset(
4729 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004730 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004731 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004732 __ Bind(slow_path->GetReturnLabel());
4733 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004734 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004735 __ b(slow_path->GetEntryLabel());
4736 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004737}
4738
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004739ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4740 return codegen_->GetAssembler();
4741}
4742
4743void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004744 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004745 Location source = move->GetSource();
4746 Location destination = move->GetDestination();
4747
4748 if (source.IsRegister()) {
4749 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004750 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004751 } else {
4752 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004753 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004754 SP, destination.GetStackIndex());
4755 }
4756 } else if (source.IsStackSlot()) {
4757 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004758 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004759 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004760 } else if (destination.IsFpuRegister()) {
4761 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004762 } else {
4763 DCHECK(destination.IsStackSlot());
4764 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4765 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4766 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004767 } else if (source.IsFpuRegister()) {
4768 if (destination.IsFpuRegister()) {
4769 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004770 } else {
4771 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004772 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4773 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004774 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004775 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004776 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4777 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004778 } else if (destination.IsRegisterPair()) {
4779 DCHECK(ExpectedPairLayout(destination));
4780 __ LoadFromOffset(
4781 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4782 } else {
4783 DCHECK(destination.IsFpuRegisterPair()) << destination;
4784 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4785 SP,
4786 source.GetStackIndex());
4787 }
4788 } else if (source.IsRegisterPair()) {
4789 if (destination.IsRegisterPair()) {
4790 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4791 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4792 } else {
4793 DCHECK(destination.IsDoubleStackSlot()) << destination;
4794 DCHECK(ExpectedPairLayout(source));
4795 __ StoreToOffset(
4796 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4797 }
4798 } else if (source.IsFpuRegisterPair()) {
4799 if (destination.IsFpuRegisterPair()) {
4800 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4801 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4802 } else {
4803 DCHECK(destination.IsDoubleStackSlot()) << destination;
4804 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4805 SP,
4806 destination.GetStackIndex());
4807 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004808 } else {
4809 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004810 HConstant* constant = source.GetConstant();
4811 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4812 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004813 if (destination.IsRegister()) {
4814 __ LoadImmediate(destination.AsRegister<Register>(), value);
4815 } else {
4816 DCHECK(destination.IsStackSlot());
4817 __ LoadImmediate(IP, value);
4818 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4819 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004820 } else if (constant->IsLongConstant()) {
4821 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004822 if (destination.IsRegisterPair()) {
4823 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4824 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004825 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004826 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004827 __ LoadImmediate(IP, Low32Bits(value));
4828 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4829 __ LoadImmediate(IP, High32Bits(value));
4830 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4831 }
4832 } else if (constant->IsDoubleConstant()) {
4833 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004834 if (destination.IsFpuRegisterPair()) {
4835 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004836 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004837 DCHECK(destination.IsDoubleStackSlot()) << destination;
4838 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004839 __ LoadImmediate(IP, Low32Bits(int_value));
4840 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4841 __ LoadImmediate(IP, High32Bits(int_value));
4842 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4843 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004844 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004845 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004846 float value = constant->AsFloatConstant()->GetValue();
4847 if (destination.IsFpuRegister()) {
4848 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4849 } else {
4850 DCHECK(destination.IsStackSlot());
4851 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4852 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4853 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004854 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004855 }
4856}
4857
4858void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4859 __ Mov(IP, reg);
4860 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4861 __ StoreToOffset(kStoreWord, IP, SP, mem);
4862}
4863
4864void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4865 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4866 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4867 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4868 SP, mem1 + stack_offset);
4869 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4870 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4871 SP, mem2 + stack_offset);
4872 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4873}
4874
4875void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004876 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004877 Location source = move->GetSource();
4878 Location destination = move->GetDestination();
4879
4880 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004881 DCHECK_NE(source.AsRegister<Register>(), IP);
4882 DCHECK_NE(destination.AsRegister<Register>(), IP);
4883 __ Mov(IP, source.AsRegister<Register>());
4884 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4885 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004886 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004887 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004888 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004889 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004890 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4891 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004892 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004893 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004894 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004895 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004896 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004897 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004898 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004899 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004900 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4901 destination.AsRegisterPairHigh<Register>(),
4902 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004903 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004904 Register low_reg = source.IsRegisterPair()
4905 ? source.AsRegisterPairLow<Register>()
4906 : destination.AsRegisterPairLow<Register>();
4907 int mem = source.IsRegisterPair()
4908 ? destination.GetStackIndex()
4909 : source.GetStackIndex();
4910 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004911 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004912 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004913 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004914 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004915 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4916 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004917 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004918 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004919 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004920 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4921 DRegister reg = source.IsFpuRegisterPair()
4922 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4923 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4924 int mem = source.IsFpuRegisterPair()
4925 ? destination.GetStackIndex()
4926 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004927 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004928 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004929 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004930 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4931 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4932 : destination.AsFpuRegister<SRegister>();
4933 int mem = source.IsFpuRegister()
4934 ? destination.GetStackIndex()
4935 : source.GetStackIndex();
4936
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004937 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004938 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004939 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004940 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004941 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4942 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004943 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004944 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004945 }
4946}
4947
4948void ParallelMoveResolverARM::SpillScratch(int reg) {
4949 __ Push(static_cast<Register>(reg));
4950}
4951
4952void ParallelMoveResolverARM::RestoreScratch(int reg) {
4953 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004954}
4955
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004956void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004957 InvokeRuntimeCallingConvention calling_convention;
4958 CodeGenerator::CreateLoadClassLocationSummary(
4959 cls,
4960 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain3b359c72015-11-17 19:35:12 +00004961 Location::RegisterLocation(R0),
4962 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004963}
4964
4965void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004966 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01004967 if (cls->NeedsAccessCheck()) {
4968 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
4969 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
4970 cls,
4971 cls->GetDexPc(),
4972 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00004973 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01004974 return;
4975 }
4976
Roland Levillain3b359c72015-11-17 19:35:12 +00004977 Location out_loc = locations->Out();
4978 Register out = out_loc.AsRegister<Register>();
Calin Juravle580b6092015-10-06 17:35:58 +01004979 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00004980
Calin Juravle580b6092015-10-06 17:35:58 +01004981 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004982 DCHECK(!cls->CanCallRuntime());
4983 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillain3b359c72015-11-17 19:35:12 +00004984 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
4985 if (kEmitCompilerReadBarrier) {
4986 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
4987 __ AddConstant(out, current_method, declaring_class_offset);
4988 // /* mirror::Class* */ out = out->Read()
4989 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
4990 } else {
4991 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
4992 __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
4993 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004994 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004995 // /* GcRoot<mirror::Class>[] */ out =
4996 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004997 __ LoadFromOffset(kLoadWord,
4998 out,
4999 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01005000 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Roland Levillain3b359c72015-11-17 19:35:12 +00005001
5002 size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5003 if (kEmitCompilerReadBarrier) {
5004 // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5005 __ AddConstant(out, out, cache_offset);
5006 // /* mirror::Class* */ out = out->Read()
5007 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5008 } else {
5009 // /* GcRoot<mirror::Class> */ out = out[type_index]
5010 __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5011 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005012
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005013 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5014 DCHECK(cls->CanCallRuntime());
5015 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5016 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5017 codegen_->AddSlowPath(slow_path);
5018 if (!cls->IsInDexCache()) {
5019 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5020 }
5021 if (cls->MustGenerateClinitCheck()) {
5022 GenerateClassInitializationCheck(slow_path, out);
5023 } else {
5024 __ Bind(slow_path->GetExitLabel());
5025 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005026 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005027 }
5028}
5029
5030void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5031 LocationSummary* locations =
5032 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5033 locations->SetInAt(0, Location::RequiresRegister());
5034 if (check->HasUses()) {
5035 locations->SetOut(Location::SameAsFirstInput());
5036 }
5037}
5038
5039void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005040 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005041 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005042 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005043 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005044 GenerateClassInitializationCheck(slow_path,
5045 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005046}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005047
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005048void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005049 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005050 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5051 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5052 __ b(slow_path->GetEntryLabel(), LT);
5053 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5054 // properly. Therefore, we do a memory fence.
5055 __ dmb(ISH);
5056 __ Bind(slow_path->GetExitLabel());
5057}
5058
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005059void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
5060 LocationSummary* locations =
5061 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005062 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005063 locations->SetOut(Location::RequiresRegister());
5064}
5065
5066void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005067 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005068 codegen_->AddSlowPath(slow_path);
5069
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005070 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005071 Location out_loc = locations->Out();
5072 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005073 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005074
5075 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5076 if (kEmitCompilerReadBarrier) {
5077 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5078 __ AddConstant(out, current_method, declaring_class_offset);
5079 // /* mirror::Class* */ out = out->Read()
5080 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5081 } else {
5082 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5083 __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5084 }
5085
5086 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
Mathieu Chartiereace4582014-11-24 18:29:54 -08005087 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Roland Levillain3b359c72015-11-17 19:35:12 +00005088
5089 size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5090 if (kEmitCompilerReadBarrier) {
5091 // /* GcRoot<mirror::String>* */ out = &out[string_index]
5092 __ AddConstant(out, out, cache_offset);
5093 // /* mirror::String* */ out = out->Read()
5094 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5095 } else {
5096 // /* GcRoot<mirror::String> */ out = out[string_index]
5097 __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5098 }
5099
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005100 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005101 __ Bind(slow_path->GetExitLabel());
5102}
5103
David Brazdilcb1c0552015-08-04 16:22:25 +01005104static int32_t GetExceptionTlsOffset() {
5105 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5106}
5107
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005108void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5109 LocationSummary* locations =
5110 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5111 locations->SetOut(Location::RequiresRegister());
5112}
5113
5114void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005115 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005116 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5117}
5118
5119void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5120 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5121}
5122
5123void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005124 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005125 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005126}
5127
5128void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5129 LocationSummary* locations =
5130 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5131 InvokeRuntimeCallingConvention calling_convention;
5132 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5133}
5134
5135void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5136 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005137 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005138 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005139}
5140
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005141void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005142 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005143 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5144 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005145 case TypeCheckKind::kExactCheck:
5146 case TypeCheckKind::kAbstractClassCheck:
5147 case TypeCheckKind::kClassHierarchyCheck:
5148 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005149 call_kind =
5150 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005151 break;
5152 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005153 case TypeCheckKind::kUnresolvedCheck:
5154 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005155 call_kind = LocationSummary::kCallOnSlowPath;
5156 break;
5157 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005158
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005159 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005160 locations->SetInAt(0, Location::RequiresRegister());
5161 locations->SetInAt(1, Location::RequiresRegister());
5162 // The "out" register is used as a temporary, so it overlaps with the inputs.
5163 // Note that TypeCheckSlowPathARM uses this register too.
5164 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5165 // When read barriers are enabled, we need a temporary register for
5166 // some cases.
5167 if (kEmitCompilerReadBarrier &&
5168 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5169 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5170 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5171 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005172 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005173}
5174
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005175void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005176 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005177 Location obj_loc = locations->InAt(0);
5178 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005179 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005180 Location out_loc = locations->Out();
5181 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005182 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005183 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5184 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5185 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005186 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005187 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005188
5189 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005190 // avoid null check if we know obj is not null.
5191 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005192 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005193 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005194
Roland Levillain3b359c72015-11-17 19:35:12 +00005195 // /* HeapReference<Class> */ out = obj->klass_
5196 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
5197 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005198
5199 switch (instruction->GetTypeCheckKind()) {
5200 case TypeCheckKind::kExactCheck: {
5201 __ cmp(out, ShifterOperand(cls));
5202 // Classes must be equal for the instanceof to succeed.
5203 __ b(&zero, NE);
5204 __ LoadImmediate(out, 1);
5205 __ b(&done);
5206 break;
5207 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005208
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005209 case TypeCheckKind::kAbstractClassCheck: {
5210 // If the class is abstract, we eagerly fetch the super class of the
5211 // object to avoid doing a comparison we know will fail.
5212 Label loop;
5213 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005214 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5215 if (kEmitCompilerReadBarrier) {
5216 // Save the value of `out` into `temp` before overwriting it
5217 // in the following move operation, as we will need it for the
5218 // read barrier below.
5219 Register temp = temp_loc.AsRegister<Register>();
5220 __ Mov(temp, out);
5221 }
5222 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005223 __ LoadFromOffset(kLoadWord, out, out, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005224 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005225 // If `out` is null, we use it for the result, and jump to `done`.
5226 __ CompareAndBranchIfZero(out, &done);
5227 __ cmp(out, ShifterOperand(cls));
5228 __ b(&loop, NE);
5229 __ LoadImmediate(out, 1);
5230 if (zero.IsLinked()) {
5231 __ b(&done);
5232 }
5233 break;
5234 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005235
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005236 case TypeCheckKind::kClassHierarchyCheck: {
5237 // Walk over the class hierarchy to find a match.
5238 Label loop, success;
5239 __ Bind(&loop);
5240 __ cmp(out, ShifterOperand(cls));
5241 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005242 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5243 if (kEmitCompilerReadBarrier) {
5244 // Save the value of `out` into `temp` before overwriting it
5245 // in the following move operation, as we will need it for the
5246 // read barrier below.
5247 Register temp = temp_loc.AsRegister<Register>();
5248 __ Mov(temp, out);
5249 }
5250 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005251 __ LoadFromOffset(kLoadWord, out, out, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005252 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005253 __ CompareAndBranchIfNonZero(out, &loop);
5254 // If `out` is null, we use it for the result, and jump to `done`.
5255 __ b(&done);
5256 __ Bind(&success);
5257 __ LoadImmediate(out, 1);
5258 if (zero.IsLinked()) {
5259 __ b(&done);
5260 }
5261 break;
5262 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005263
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005264 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005265 // Do an exact check.
5266 Label exact_check;
5267 __ cmp(out, ShifterOperand(cls));
5268 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005269 // Otherwise, we need to check that the object's class is a non-primitive array.
5270 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5271 if (kEmitCompilerReadBarrier) {
5272 // Save the value of `out` into `temp` before overwriting it
5273 // in the following move operation, as we will need it for the
5274 // read barrier below.
5275 Register temp = temp_loc.AsRegister<Register>();
5276 __ Mov(temp, out);
5277 }
5278 // /* HeapReference<Class> */ out = out->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005279 __ LoadFromOffset(kLoadWord, out, out, component_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005280 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005281 // If `out` is null, we use it for the result, and jump to `done`.
5282 __ CompareAndBranchIfZero(out, &done);
5283 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5284 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5285 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005286 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005287 __ LoadImmediate(out, 1);
5288 __ b(&done);
5289 break;
5290 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005291
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005292 case TypeCheckKind::kArrayCheck: {
5293 __ cmp(out, ShifterOperand(cls));
5294 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005295 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5296 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005297 codegen_->AddSlowPath(slow_path);
5298 __ b(slow_path->GetEntryLabel(), NE);
5299 __ LoadImmediate(out, 1);
5300 if (zero.IsLinked()) {
5301 __ b(&done);
5302 }
5303 break;
5304 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005305
Calin Juravle98893e12015-10-02 21:05:03 +01005306 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005307 case TypeCheckKind::kInterfaceCheck: {
5308 // Note that we indeed only call on slow path, but we always go
5309 // into the slow path for the unresolved & interface check
5310 // cases.
5311 //
5312 // We cannot directly call the InstanceofNonTrivial runtime
5313 // entry point without resorting to a type checking slow path
5314 // here (i.e. by calling InvokeRuntime directly), as it would
5315 // require to assign fixed registers for the inputs of this
5316 // HInstanceOf instruction (following the runtime calling
5317 // convention), which might be cluttered by the potential first
5318 // read barrier emission at the beginning of this method.
5319 DCHECK(locations->OnlyCallsOnSlowPath());
5320 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5321 /* is_fatal */ false);
5322 codegen_->AddSlowPath(slow_path);
5323 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005324 if (zero.IsLinked()) {
5325 __ b(&done);
5326 }
5327 break;
5328 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005329 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005330
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005331 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005332 __ Bind(&zero);
5333 __ LoadImmediate(out, 0);
5334 }
5335
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005336 if (done.IsLinked()) {
5337 __ Bind(&done);
5338 }
5339
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005340 if (slow_path != nullptr) {
5341 __ Bind(slow_path->GetExitLabel());
5342 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005343}
5344
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005345void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005346 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5347 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5348
Roland Levillain3b359c72015-11-17 19:35:12 +00005349 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5350 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005351 case TypeCheckKind::kExactCheck:
5352 case TypeCheckKind::kAbstractClassCheck:
5353 case TypeCheckKind::kClassHierarchyCheck:
5354 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005355 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5356 LocationSummary::kCallOnSlowPath :
5357 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005358 break;
5359 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005360 case TypeCheckKind::kUnresolvedCheck:
5361 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005362 call_kind = LocationSummary::kCallOnSlowPath;
5363 break;
5364 }
5365
Roland Levillain3b359c72015-11-17 19:35:12 +00005366 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5367 locations->SetInAt(0, Location::RequiresRegister());
5368 locations->SetInAt(1, Location::RequiresRegister());
5369 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5370 locations->AddTemp(Location::RequiresRegister());
5371 // When read barriers are enabled, we need an additional temporary
5372 // register for some cases.
5373 if (kEmitCompilerReadBarrier &&
5374 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5375 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5376 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005377 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005378 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005379}
5380
5381void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5382 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005383 Location obj_loc = locations->InAt(0);
5384 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005385 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005386 Location temp_loc = locations->GetTemp(0);
5387 Register temp = temp_loc.AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005388 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005389 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5390 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5391 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005392
Roland Levillain3b359c72015-11-17 19:35:12 +00005393 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5394 bool is_type_check_slow_path_fatal =
5395 (type_check_kind == TypeCheckKind::kExactCheck ||
5396 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5397 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5398 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5399 !instruction->CanThrowIntoCatchBlock();
5400 SlowPathCode* type_check_slow_path =
5401 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5402 is_type_check_slow_path_fatal);
5403 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005404
5405 Label done;
5406 // Avoid null check if we know obj is not null.
5407 if (instruction->MustDoNullCheck()) {
5408 __ CompareAndBranchIfZero(obj, &done);
5409 }
5410
Roland Levillain3b359c72015-11-17 19:35:12 +00005411 // /* HeapReference<Class> */ temp = obj->klass_
5412 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5413 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005414
Roland Levillain3b359c72015-11-17 19:35:12 +00005415 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005416 case TypeCheckKind::kExactCheck:
5417 case TypeCheckKind::kArrayCheck: {
5418 __ cmp(temp, ShifterOperand(cls));
5419 // Jump to slow path for throwing the exception or doing a
5420 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005421 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005422 break;
5423 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005424
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005425 case TypeCheckKind::kAbstractClassCheck: {
5426 // If the class is abstract, we eagerly fetch the super class of the
5427 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005428 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005429 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005430 Location temp2_loc =
5431 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5432 if (kEmitCompilerReadBarrier) {
5433 // Save the value of `temp` into `temp2` before overwriting it
5434 // in the following move operation, as we will need it for the
5435 // read barrier below.
5436 Register temp2 = temp2_loc.AsRegister<Register>();
5437 __ Mov(temp2, temp);
5438 }
5439 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005440 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005441 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5442
5443 // If the class reference currently in `temp` is not null, jump
5444 // to the `compare_classes` label to compare it with the checked
5445 // class.
5446 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5447 // Otherwise, jump to the slow path to throw the exception.
5448 //
5449 // But before, move back the object's class into `temp` before
5450 // going into the slow path, as it has been overwritten in the
5451 // meantime.
5452 // /* HeapReference<Class> */ temp = obj->klass_
5453 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5454 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5455 __ b(type_check_slow_path->GetEntryLabel());
5456
5457 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005458 __ cmp(temp, ShifterOperand(cls));
5459 __ b(&loop, NE);
5460 break;
5461 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005462
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005463 case TypeCheckKind::kClassHierarchyCheck: {
5464 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005465 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005466 __ Bind(&loop);
5467 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005468 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005469
5470 Location temp2_loc =
5471 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5472 if (kEmitCompilerReadBarrier) {
5473 // Save the value of `temp` into `temp2` before overwriting it
5474 // in the following move operation, as we will need it for the
5475 // read barrier below.
5476 Register temp2 = temp2_loc.AsRegister<Register>();
5477 __ Mov(temp2, temp);
5478 }
5479 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005480 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005481 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5482
5483 // If the class reference currently in `temp` is not null, jump
5484 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005485 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005486 // Otherwise, jump to the slow path to throw the exception.
5487 //
5488 // But before, move back the object's class into `temp` before
5489 // going into the slow path, as it has been overwritten in the
5490 // meantime.
5491 // /* HeapReference<Class> */ temp = obj->klass_
5492 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5493 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5494 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005495 break;
5496 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005497
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005498 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005499 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005500 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005501 __ cmp(temp, ShifterOperand(cls));
5502 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005503
5504 // Otherwise, we need to check that the object's class is a non-primitive array.
5505 Location temp2_loc =
5506 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5507 if (kEmitCompilerReadBarrier) {
5508 // Save the value of `temp` into `temp2` before overwriting it
5509 // in the following move operation, as we will need it for the
5510 // read barrier below.
5511 Register temp2 = temp2_loc.AsRegister<Register>();
5512 __ Mov(temp2, temp);
5513 }
5514 // /* HeapReference<Class> */ temp = temp->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005515 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005516 codegen_->MaybeGenerateReadBarrier(
5517 instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5518
5519 // If the component type is not null (i.e. the object is indeed
5520 // an array), jump to label `check_non_primitive_component_type`
5521 // to further check that this component type is not a primitive
5522 // type.
5523 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5524 // Otherwise, jump to the slow path to throw the exception.
5525 //
5526 // But before, move back the object's class into `temp` before
5527 // going into the slow path, as it has been overwritten in the
5528 // meantime.
5529 // /* HeapReference<Class> */ temp = obj->klass_
5530 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5531 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5532 __ b(type_check_slow_path->GetEntryLabel());
5533
5534 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005535 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005536 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5537 __ CompareAndBranchIfZero(temp, &done);
5538 // Same comment as above regarding `temp` and the slow path.
5539 // /* HeapReference<Class> */ temp = obj->klass_
5540 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5541 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5542 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005543 break;
5544 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005545
Calin Juravle98893e12015-10-02 21:05:03 +01005546 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005547 case TypeCheckKind::kInterfaceCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005548 // We always go into the type check slow path for the unresolved &
5549 // interface check cases.
5550 //
5551 // We cannot directly call the CheckCast runtime entry point
5552 // without resorting to a type checking slow path here (i.e. by
5553 // calling InvokeRuntime directly), as it would require to
5554 // assign fixed registers for the inputs of this HInstanceOf
5555 // instruction (following the runtime calling convention), which
5556 // might be cluttered by the potential first read barrier
5557 // emission at the beginning of this method.
5558 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005559 break;
5560 }
5561 __ Bind(&done);
5562
Roland Levillain3b359c72015-11-17 19:35:12 +00005563 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005564}
5565
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005566void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5567 LocationSummary* locations =
5568 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5569 InvokeRuntimeCallingConvention calling_convention;
5570 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5571}
5572
5573void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5574 codegen_->InvokeRuntime(instruction->IsEnter()
5575 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5576 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005577 instruction->GetDexPc(),
5578 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005579 if (instruction->IsEnter()) {
5580 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5581 } else {
5582 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5583 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005584}
5585
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005586void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5587void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5588void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005589
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005590void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005591 LocationSummary* locations =
5592 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5593 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5594 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005595 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005596 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005597 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005598 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005599}
5600
5601void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5602 HandleBitwiseOperation(instruction);
5603}
5604
5605void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5606 HandleBitwiseOperation(instruction);
5607}
5608
5609void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5610 HandleBitwiseOperation(instruction);
5611}
5612
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005613void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5614 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5615 if (value == 0xffffffffu) {
5616 if (out != first) {
5617 __ mov(out, ShifterOperand(first));
5618 }
5619 return;
5620 }
5621 if (value == 0u) {
5622 __ mov(out, ShifterOperand(0));
5623 return;
5624 }
5625 ShifterOperand so;
5626 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5627 __ and_(out, first, so);
5628 } else {
5629 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5630 __ bic(out, first, ShifterOperand(~value));
5631 }
5632}
5633
5634void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5635 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5636 if (value == 0u) {
5637 if (out != first) {
5638 __ mov(out, ShifterOperand(first));
5639 }
5640 return;
5641 }
5642 if (value == 0xffffffffu) {
5643 __ mvn(out, ShifterOperand(0));
5644 return;
5645 }
5646 ShifterOperand so;
5647 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5648 __ orr(out, first, so);
5649 } else {
5650 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5651 __ orn(out, first, ShifterOperand(~value));
5652 }
5653}
5654
5655void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5656 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5657 if (value == 0u) {
5658 if (out != first) {
5659 __ mov(out, ShifterOperand(first));
5660 }
5661 return;
5662 }
5663 __ eor(out, first, ShifterOperand(value));
5664}
5665
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005666void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5667 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005668 Location first = locations->InAt(0);
5669 Location second = locations->InAt(1);
5670 Location out = locations->Out();
5671
5672 if (second.IsConstant()) {
5673 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5674 uint32_t value_low = Low32Bits(value);
5675 if (instruction->GetResultType() == Primitive::kPrimInt) {
5676 Register first_reg = first.AsRegister<Register>();
5677 Register out_reg = out.AsRegister<Register>();
5678 if (instruction->IsAnd()) {
5679 GenerateAndConst(out_reg, first_reg, value_low);
5680 } else if (instruction->IsOr()) {
5681 GenerateOrrConst(out_reg, first_reg, value_low);
5682 } else {
5683 DCHECK(instruction->IsXor());
5684 GenerateEorConst(out_reg, first_reg, value_low);
5685 }
5686 } else {
5687 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5688 uint32_t value_high = High32Bits(value);
5689 Register first_low = first.AsRegisterPairLow<Register>();
5690 Register first_high = first.AsRegisterPairHigh<Register>();
5691 Register out_low = out.AsRegisterPairLow<Register>();
5692 Register out_high = out.AsRegisterPairHigh<Register>();
5693 if (instruction->IsAnd()) {
5694 GenerateAndConst(out_low, first_low, value_low);
5695 GenerateAndConst(out_high, first_high, value_high);
5696 } else if (instruction->IsOr()) {
5697 GenerateOrrConst(out_low, first_low, value_low);
5698 GenerateOrrConst(out_high, first_high, value_high);
5699 } else {
5700 DCHECK(instruction->IsXor());
5701 GenerateEorConst(out_low, first_low, value_low);
5702 GenerateEorConst(out_high, first_high, value_high);
5703 }
5704 }
5705 return;
5706 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005707
5708 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005709 Register first_reg = first.AsRegister<Register>();
5710 ShifterOperand second_reg(second.AsRegister<Register>());
5711 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005712 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005713 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005714 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005715 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005716 } else {
5717 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005718 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005719 }
5720 } else {
5721 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005722 Register first_low = first.AsRegisterPairLow<Register>();
5723 Register first_high = first.AsRegisterPairHigh<Register>();
5724 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5725 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5726 Register out_low = out.AsRegisterPairLow<Register>();
5727 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005728 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005729 __ and_(out_low, first_low, second_low);
5730 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005731 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005732 __ orr(out_low, first_low, second_low);
5733 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005734 } else {
5735 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005736 __ eor(out_low, first_low, second_low);
5737 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005738 }
5739 }
5740}
5741
Roland Levillain3b359c72015-11-17 19:35:12 +00005742void CodeGeneratorARM::GenerateReadBarrier(HInstruction* instruction,
5743 Location out,
5744 Location ref,
5745 Location obj,
5746 uint32_t offset,
5747 Location index) {
5748 DCHECK(kEmitCompilerReadBarrier);
5749
5750 // If heap poisoning is enabled, the unpoisoning of the loaded
5751 // reference will be carried out by the runtime within the slow
5752 // path.
5753 //
5754 // Note that `ref` currently does not get unpoisoned (when heap
5755 // poisoning is enabled), which is alright as the `ref` argument is
5756 // not used by the artReadBarrierSlow entry point.
5757 //
5758 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5759 SlowPathCode* slow_path = new (GetGraph()->GetArena())
5760 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
5761 AddSlowPath(slow_path);
5762
5763 // TODO: When read barrier has a fast path, add it here.
5764 /* Currently the read barrier call is inserted after the original load.
5765 * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5766 * original load. This load-load ordering is required by the read barrier.
5767 * The fast path/slow path (for Baker's algorithm) should look like:
5768 *
5769 * bool isGray = obj.LockWord & kReadBarrierMask;
5770 * lfence; // load fence or artificial data dependence to prevent load-load reordering
5771 * ref = obj.field; // this is the original load
5772 * if (isGray) {
5773 * ref = Mark(ref); // ideally the slow path just does Mark(ref)
5774 * }
5775 */
5776
5777 __ b(slow_path->GetEntryLabel());
5778 __ Bind(slow_path->GetExitLabel());
5779}
5780
5781void CodeGeneratorARM::MaybeGenerateReadBarrier(HInstruction* instruction,
5782 Location out,
5783 Location ref,
5784 Location obj,
5785 uint32_t offset,
5786 Location index) {
5787 if (kEmitCompilerReadBarrier) {
5788 // If heap poisoning is enabled, unpoisoning will be taken care of
5789 // by the runtime within the slow path.
5790 GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5791 } else if (kPoisonHeapReferences) {
5792 __ UnpoisonHeapReference(out.AsRegister<Register>());
5793 }
5794}
5795
5796void CodeGeneratorARM::GenerateReadBarrierForRoot(HInstruction* instruction,
5797 Location out,
5798 Location root) {
5799 DCHECK(kEmitCompilerReadBarrier);
5800
5801 // Note that GC roots are not affected by heap poisoning, so we do
5802 // not need to do anything special for this here.
5803 SlowPathCode* slow_path =
5804 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
5805 AddSlowPath(slow_path);
5806
5807 // TODO: Implement a fast path for ReadBarrierForRoot, performing
5808 // the following operation (for Baker's algorithm):
5809 //
5810 // if (thread.tls32_.is_gc_marking) {
5811 // root = Mark(root);
5812 // }
5813
5814 __ b(slow_path->GetEntryLabel());
5815 __ Bind(slow_path->GetExitLabel());
5816}
5817
Vladimir Markodc151b22015-10-15 18:02:30 +01005818HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5819 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5820 MethodReference target_method) {
5821 if (desired_dispatch_info.method_load_kind ==
5822 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative) {
5823 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
5824 return HInvokeStaticOrDirect::DispatchInfo {
5825 HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
5826 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
5827 0u,
5828 0u
5829 };
5830 }
5831 if (desired_dispatch_info.code_ptr_location ==
5832 HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5833 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5834 if (&outer_dex_file != target_method.dex_file) {
5835 // Calls across dex files are more likely to exceed the available BL range,
5836 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5837 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5838 (desired_dispatch_info.method_load_kind ==
5839 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
5840 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
5841 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
5842 return HInvokeStaticOrDirect::DispatchInfo {
5843 desired_dispatch_info.method_load_kind,
5844 code_ptr_location,
5845 desired_dispatch_info.method_load_data,
5846 0u
5847 };
5848 }
5849 }
5850 return desired_dispatch_info;
5851}
5852
Nicolas Geoffray38207af2015-06-01 15:46:22 +01005853void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00005854 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00005855 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00005856 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5857 // LR = code address from literal pool with link-time patch.
5858 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00005859 break;
5860 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5861 // LR = invoke->GetDirectCodePtr();
5862 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00005863 break;
5864 default:
5865 break;
5866 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005867
Vladimir Marko58155012015-08-19 12:49:41 +00005868 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
5869 switch (invoke->GetMethodLoadKind()) {
5870 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
5871 // temp = thread->string_init_entrypoint
5872 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
5873 break;
5874 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00005875 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00005876 break;
5877 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
5878 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
5879 break;
5880 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
5881 __ LoadLiteral(temp.AsRegister<Register>(),
5882 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
5883 break;
5884 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005885 // TODO: Implement this type.
5886 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
5887 LOG(FATAL) << "Unsupported";
5888 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +00005889 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00005890 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00005891 Register method_reg;
5892 Register reg = temp.AsRegister<Register>();
5893 if (current_method.IsRegister()) {
5894 method_reg = current_method.AsRegister<Register>();
5895 } else {
5896 DCHECK(invoke->GetLocations()->Intrinsified());
5897 DCHECK(!current_method.IsValid());
5898 method_reg = reg;
5899 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
5900 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005901 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
5902 __ LoadFromOffset(kLoadWord,
5903 reg,
5904 method_reg,
5905 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00005906 // temp = temp[index_in_cache]
5907 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
5908 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
5909 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01005910 }
Vladimir Marko58155012015-08-19 12:49:41 +00005911 }
5912
5913 switch (invoke->GetCodePtrLocation()) {
5914 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
5915 __ bl(GetFrameEntryLabel());
5916 break;
5917 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005918 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005919 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01005920 // Arbitrarily branch to the BL itself, override at link time.
5921 __ bl(&relative_call_patches_.back().label);
5922 break;
Vladimir Marko58155012015-08-19 12:49:41 +00005923 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5924 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5925 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00005926 // LR()
5927 __ blx(LR);
5928 break;
5929 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5930 // LR = callee_method->entry_point_from_quick_compiled_code_
5931 __ LoadFromOffset(
5932 kLoadWord, LR, callee_method.AsRegister<Register>(),
5933 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
5934 // LR()
5935 __ blx(LR);
5936 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005937 }
5938
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005939 DCHECK(!IsLeafMethod());
5940}
5941
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005942void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
5943 Register temp = temp_location.AsRegister<Register>();
5944 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5945 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
5946 LocationSummary* locations = invoke->GetLocations();
5947 Location receiver = locations->InAt(0);
5948 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005949 DCHECK(receiver.IsRegister());
Roland Levillain3b359c72015-11-17 19:35:12 +00005950 // /* HeapReference<Class> */ temp = receiver->klass_
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005951 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
5952 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00005953 // Instead of simply (possibly) unpoisoning `temp` here, we should
5954 // emit a read barrier for the previous class reference load.
5955 // However this is not required in practice, as this is an
5956 // intermediate/temporary reference and because the current
5957 // concurrent copying collector keeps the from-space memory
5958 // intact/accessible until the end of the marking phase (the
5959 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005960 __ MaybeUnpoisonHeapReference(temp);
5961 // temp = temp->GetMethodAt(method_offset);
5962 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5963 kArmWordSize).Int32Value();
5964 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5965 // LR = temp->GetEntryPoint();
5966 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
5967 // LR();
5968 __ blx(LR);
5969}
5970
Vladimir Marko58155012015-08-19 12:49:41 +00005971void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
5972 DCHECK(linker_patches->empty());
5973 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
5974 linker_patches->reserve(size);
5975 for (const auto& entry : method_patches_) {
5976 const MethodReference& target_method = entry.first;
5977 Literal* literal = entry.second;
5978 DCHECK(literal->GetLabel()->IsBound());
5979 uint32_t literal_offset = literal->GetLabel()->Position();
5980 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
5981 target_method.dex_file,
5982 target_method.dex_method_index));
5983 }
5984 for (const auto& entry : call_patches_) {
5985 const MethodReference& target_method = entry.first;
5986 Literal* literal = entry.second;
5987 DCHECK(literal->GetLabel()->IsBound());
5988 uint32_t literal_offset = literal->GetLabel()->Position();
5989 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
5990 target_method.dex_file,
5991 target_method.dex_method_index));
5992 }
5993 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
5994 uint32_t literal_offset = info.label.Position();
5995 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
5996 info.target_method.dex_file,
5997 info.target_method.dex_method_index));
5998 }
5999}
6000
6001Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6002 MethodToLiteralMap* map) {
6003 // Look up the literal for target_method.
6004 auto lb = map->lower_bound(target_method);
6005 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
6006 return lb->second;
6007 }
6008 // We don't have a literal for this method yet, insert a new one.
6009 Literal* literal = __ NewLiteral<uint32_t>(0u);
6010 map->PutBefore(lb, target_method, literal);
6011 return literal;
6012}
6013
6014Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6015 return DeduplicateMethodLiteral(target_method, &method_patches_);
6016}
6017
6018Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6019 return DeduplicateMethodLiteral(target_method, &call_patches_);
6020}
6021
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006022void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006023 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006024 LOG(FATAL) << "Unreachable";
6025}
6026
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006027void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006028 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006029 LOG(FATAL) << "Unreachable";
6030}
6031
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01006032void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
6033 DCHECK(codegen_->IsBaseline());
6034 LocationSummary* locations =
6035 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6036 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
6037}
6038
6039void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6040 DCHECK(codegen_->IsBaseline());
6041 // Will be generated at use site.
6042}
6043
Mark Mendellfe57faa2015-09-18 09:26:15 -04006044// Simple implementation of packed switch - generate cascaded compare/jumps.
6045void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6046 LocationSummary* locations =
6047 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6048 locations->SetInAt(0, Location::RequiresRegister());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006049 if (switch_instr->GetNumEntries() >= kPackedSwitchJumpTableThreshold &&
6050 codegen_->GetAssembler()->IsThumb()) {
6051 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6052 if (switch_instr->GetStartValue() != 0) {
6053 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6054 }
6055 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006056}
6057
6058void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6059 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006060 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006061 LocationSummary* locations = switch_instr->GetLocations();
6062 Register value_reg = locations->InAt(0).AsRegister<Register>();
6063 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6064
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006065 if (num_entries < kPackedSwitchJumpTableThreshold || !codegen_->GetAssembler()->IsThumb()) {
6066 // Create a series of compare/jumps.
6067 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6068 for (uint32_t i = 0; i < num_entries; i++) {
6069 GenerateCompareWithImmediate(value_reg, lower_bound + i);
6070 __ b(codegen_->GetLabelOf(successors[i]), EQ);
6071 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006072
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006073 // And the default for any other value.
6074 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6075 __ b(codegen_->GetLabelOf(default_block));
6076 }
6077 } else {
6078 // Create a table lookup.
6079 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6080
6081 // Materialize a pointer to the switch table
6082 std::vector<Label*> labels(num_entries);
6083 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6084 for (uint32_t i = 0; i < num_entries; i++) {
6085 labels[i] = codegen_->GetLabelOf(successors[i]);
6086 }
6087 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6088
6089 // Remove the bias.
6090 Register key_reg;
6091 if (lower_bound != 0) {
6092 key_reg = locations->GetTemp(1).AsRegister<Register>();
6093 __ AddConstant(key_reg, value_reg, -lower_bound);
6094 } else {
6095 key_reg = value_reg;
6096 }
6097
6098 // Check whether the value is in the table, jump to default block if not.
6099 __ CmpConstant(key_reg, num_entries - 1);
6100 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6101
6102 // Load the displacement from the table.
6103 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6104
6105 // Dispatch is a direct add to the PC (for Thumb2).
6106 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006107 }
6108}
6109
Andreas Gampe85b62f22015-09-09 13:15:38 -07006110void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6111 if (!trg.IsValid()) {
6112 DCHECK(type == Primitive::kPrimVoid);
6113 return;
6114 }
6115
6116 DCHECK_NE(type, Primitive::kPrimVoid);
6117
6118 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6119 if (return_loc.Equals(trg)) {
6120 return;
6121 }
6122
6123 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6124 // with the last branch.
6125 if (type == Primitive::kPrimLong) {
6126 HParallelMove parallel_move(GetGraph()->GetArena());
6127 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6128 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6129 GetMoveResolver()->EmitNativeCode(&parallel_move);
6130 } else if (type == Primitive::kPrimDouble) {
6131 HParallelMove parallel_move(GetGraph()->GetArena());
6132 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6133 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6134 GetMoveResolver()->EmitNativeCode(&parallel_move);
6135 } else {
6136 // Let the parallel move resolver take care of all of this.
6137 HParallelMove parallel_move(GetGraph()->GetArena());
6138 parallel_move.AddMove(return_loc, trg, type, nullptr);
6139 GetMoveResolver()->EmitNativeCode(&parallel_move);
6140 }
6141}
6142
Roland Levillain4d027112015-07-01 15:41:14 +01006143#undef __
6144#undef QUICK_ENTRY_POINT
6145
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006146} // namespace arm
6147} // namespace art