blob: 680b200c69ae444665e9fd1f21fdcaed2f7ff6f7 [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
Vladimir Markof3e0ee22015-12-17 15:23:13 +000062static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070063
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)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000727 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
728 dex_cache_arrays_base_labels_(std::less<HArmDexCacheArraysBase*>(),
729 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700730 // Always save the LR register to mimic Quick.
731 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100732}
733
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000734void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
735 // Ensure that we fix up branches and literal loads and emit the literal pool.
736 __ FinalizeCode();
737
738 // Adjust native pc offsets in stack maps.
739 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
740 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
741 uint32_t new_position = __ GetAdjustedPosition(old_position);
742 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
743 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100744 // Adjust pc offsets for the disassembly information.
745 if (disasm_info_ != nullptr) {
746 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
747 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
748 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
749 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
750 it.second.start = __ GetAdjustedPosition(it.second.start);
751 it.second.end = __ GetAdjustedPosition(it.second.end);
752 }
753 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
754 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
755 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
756 }
757 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000758
759 CodeGenerator::Finalize(allocator);
760}
761
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100762Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100763 switch (type) {
764 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100765 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100766 ArmManagedRegister pair =
767 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100768 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
769 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
770
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100771 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
772 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100773 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100774 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100775 }
776
777 case Primitive::kPrimByte:
778 case Primitive::kPrimBoolean:
779 case Primitive::kPrimChar:
780 case Primitive::kPrimShort:
781 case Primitive::kPrimInt:
782 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100783 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100784 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100785 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
786 ArmManagedRegister current =
787 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
788 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100789 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100790 }
791 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100792 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100793 }
794
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000795 case Primitive::kPrimFloat: {
796 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100797 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100798 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100799
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000800 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000801 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
802 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000803 return Location::FpuRegisterPairLocation(reg, reg + 1);
804 }
805
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100806 case Primitive::kPrimVoid:
807 LOG(FATAL) << "Unreachable type " << type;
808 }
809
Roland Levillain3b359c72015-11-17 19:35:12 +0000810 return Location::NoLocation();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100811}
812
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000813void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100814 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100815 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100816
817 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100818 blocked_core_registers_[SP] = true;
819 blocked_core_registers_[LR] = true;
820 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100821
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100822 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100823 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100824
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100825 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100826 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100827
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000828 if (is_baseline) {
829 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
830 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
831 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000832
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000833 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100834 }
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000835
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100836 if (is_baseline || GetGraph()->IsDebuggable()) {
837 // Stubs do not save callee-save floating point registers. If the graph
838 // is debuggable, we need to deal with these registers differently. For
839 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000840 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
841 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
842 }
843 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100844
845 UpdateBlockedPairRegisters();
846}
847
848void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
849 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
850 ArmManagedRegister current =
851 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
852 if (blocked_core_registers_[current.AsRegisterPairLow()]
853 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
854 blocked_register_pairs_[i] = true;
855 }
856 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100857}
858
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100859InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
860 : HGraphVisitor(graph),
861 assembler_(codegen->GetAssembler()),
862 codegen_(codegen) {}
863
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000864void CodeGeneratorARM::ComputeSpillMask() {
865 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000866 // Save one extra register for baseline. Note that on thumb2, there is no easy
867 // instruction to restore just the PC, so this actually helps both baseline
868 // and non-baseline to save and restore at least two registers at entry and exit.
869 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000870 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
871 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
872 // We use vpush and vpop for saving and restoring floating point registers, which take
873 // a SRegister and the number of registers to save/restore after that SRegister. We
874 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
875 // but in the range.
876 if (fpu_spill_mask_ != 0) {
877 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
878 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
879 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
880 fpu_spill_mask_ |= (1 << i);
881 }
882 }
883}
884
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100885static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100886 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100887}
888
889static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100890 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100891}
892
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000893void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000894 bool skip_overflow_check =
895 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000896 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000897 __ Bind(&frame_entry_label_);
898
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000899 if (HasEmptyFrame()) {
900 return;
901 }
902
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100903 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000904 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
905 __ LoadFromOffset(kLoadWord, IP, IP, 0);
906 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100907 }
908
Andreas Gampe501fd632015-09-10 16:11:06 -0700909 __ PushList(core_spill_mask_);
910 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
911 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000912 if (fpu_spill_mask_ != 0) {
913 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
914 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100915 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100916 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000917 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100918 int adjust = GetFrameSize() - FrameEntrySpillSize();
919 __ AddConstant(SP, -adjust);
920 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100921 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000922}
923
924void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000925 if (HasEmptyFrame()) {
926 __ bx(LR);
927 return;
928 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100929 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100930 int adjust = GetFrameSize() - FrameEntrySpillSize();
931 __ AddConstant(SP, adjust);
932 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000933 if (fpu_spill_mask_ != 0) {
934 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
935 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100936 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
937 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000938 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700939 // Pop LR into PC to return.
940 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
941 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
942 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100943 __ cfi().RestoreState();
944 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000945}
946
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100947void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700948 Label* label = GetLabelOf(block);
949 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000950}
951
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100952Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
953 switch (load->GetType()) {
954 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100955 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100956 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100957
958 case Primitive::kPrimInt:
959 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100960 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100961 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100962
963 case Primitive::kPrimBoolean:
964 case Primitive::kPrimByte:
965 case Primitive::kPrimChar:
966 case Primitive::kPrimShort:
967 case Primitive::kPrimVoid:
968 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700969 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100970 }
971
972 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700973 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100974}
975
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100976Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100977 switch (type) {
978 case Primitive::kPrimBoolean:
979 case Primitive::kPrimByte:
980 case Primitive::kPrimChar:
981 case Primitive::kPrimShort:
982 case Primitive::kPrimInt:
983 case Primitive::kPrimNot: {
984 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000985 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100986 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100987 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100988 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000989 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100990 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100991 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100992
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000993 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100994 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000995 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100996 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000997 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100998 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000999 if (calling_convention.GetRegisterAt(index) == R1) {
1000 // Skip R1, and use R2_R3 instead.
1001 gp_index_++;
1002 index++;
1003 }
1004 }
1005 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1006 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001007 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001008
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001009 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001010 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001011 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001012 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1013 }
1014 }
1015
1016 case Primitive::kPrimFloat: {
1017 uint32_t stack_index = stack_index_++;
1018 if (float_index_ % 2 == 0) {
1019 float_index_ = std::max(double_index_, float_index_);
1020 }
1021 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1022 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1023 } else {
1024 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1025 }
1026 }
1027
1028 case Primitive::kPrimDouble: {
1029 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1030 uint32_t stack_index = stack_index_;
1031 stack_index_ += 2;
1032 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1033 uint32_t index = double_index_;
1034 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001035 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001036 calling_convention.GetFpuRegisterAt(index),
1037 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001038 DCHECK(ExpectedPairLayout(result));
1039 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001040 } else {
1041 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001042 }
1043 }
1044
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001045 case Primitive::kPrimVoid:
1046 LOG(FATAL) << "Unexpected parameter type " << type;
1047 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001048 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001049 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001050}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001051
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001052Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001053 switch (type) {
1054 case Primitive::kPrimBoolean:
1055 case Primitive::kPrimByte:
1056 case Primitive::kPrimChar:
1057 case Primitive::kPrimShort:
1058 case Primitive::kPrimInt:
1059 case Primitive::kPrimNot: {
1060 return Location::RegisterLocation(R0);
1061 }
1062
1063 case Primitive::kPrimFloat: {
1064 return Location::FpuRegisterLocation(S0);
1065 }
1066
1067 case Primitive::kPrimLong: {
1068 return Location::RegisterPairLocation(R0, R1);
1069 }
1070
1071 case Primitive::kPrimDouble: {
1072 return Location::FpuRegisterPairLocation(S0, S1);
1073 }
1074
1075 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001076 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001077 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001078
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001079 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001080}
1081
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001082Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1083 return Location::RegisterLocation(kMethodRegisterArgument);
1084}
1085
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001086void CodeGeneratorARM::Move32(Location destination, Location source) {
1087 if (source.Equals(destination)) {
1088 return;
1089 }
1090 if (destination.IsRegister()) {
1091 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001092 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001093 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001094 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001095 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001096 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 } else if (destination.IsFpuRegister()) {
1099 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001100 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001101 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001104 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001105 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001107 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001108 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001110 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001111 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001112 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001113 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001114 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1115 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001116 }
1117 }
1118}
1119
1120void CodeGeneratorARM::Move64(Location destination, Location source) {
1121 if (source.Equals(destination)) {
1122 return;
1123 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001124 if (destination.IsRegisterPair()) {
1125 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001126 EmitParallelMoves(
1127 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1128 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001129 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001130 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001131 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1132 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001133 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001134 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001135 } else if (source.IsFpuRegisterPair()) {
1136 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1137 destination.AsRegisterPairHigh<Register>(),
1138 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001139 } else {
1140 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001141 DCHECK(ExpectedPairLayout(destination));
1142 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1143 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001144 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001145 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001146 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001147 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1148 SP,
1149 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001150 } else if (source.IsRegisterPair()) {
1151 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1152 source.AsRegisterPairLow<Register>(),
1153 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001154 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001155 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001156 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001157 } else {
1158 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001159 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001160 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001161 if (source.AsRegisterPairLow<Register>() == R1) {
1162 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001163 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1164 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001165 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001166 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001167 SP, destination.GetStackIndex());
1168 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001169 } else if (source.IsFpuRegisterPair()) {
1170 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1171 SP,
1172 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001173 } else {
1174 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001175 EmitParallelMoves(
1176 Location::StackSlot(source.GetStackIndex()),
1177 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001178 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001179 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001180 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1181 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001182 }
1183 }
1184}
1185
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001186void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001187 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001188 if (instruction->IsCurrentMethod()) {
1189 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
1190 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001191 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01001192 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +00001193 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001194 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
1195 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +00001196 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001197 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +00001198 } else {
1199 DCHECK(location.IsStackSlot());
1200 __ LoadImmediate(IP, value);
1201 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1202 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001203 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +00001204 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +00001205 int64_t value = const_to_move->AsLongConstant()->GetValue();
1206 if (location.IsRegisterPair()) {
1207 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
1208 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
1209 } else {
1210 DCHECK(location.IsDoubleStackSlot());
1211 __ LoadImmediate(IP, Low32Bits(value));
1212 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
1213 __ LoadImmediate(IP, High32Bits(value));
1214 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
1215 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001216 }
Roland Levillain476df552014-10-09 17:51:36 +01001217 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001218 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
1219 switch (instruction->GetType()) {
1220 case Primitive::kPrimBoolean:
1221 case Primitive::kPrimByte:
1222 case Primitive::kPrimChar:
1223 case Primitive::kPrimShort:
1224 case Primitive::kPrimInt:
1225 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001226 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001227 Move32(location, Location::StackSlot(stack_slot));
1228 break;
1229
1230 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001231 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001232 Move64(location, Location::DoubleStackSlot(stack_slot));
1233 break;
1234
1235 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001236 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001237 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001238 } else if (instruction->IsTemporary()) {
1239 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +00001240 if (temp_location.IsStackSlot()) {
1241 Move32(location, temp_location);
1242 } else {
1243 DCHECK(temp_location.IsDoubleStackSlot());
1244 Move64(location, temp_location);
1245 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001246 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001247 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001248 switch (instruction->GetType()) {
1249 case Primitive::kPrimBoolean:
1250 case Primitive::kPrimByte:
1251 case Primitive::kPrimChar:
1252 case Primitive::kPrimShort:
1253 case Primitive::kPrimNot:
1254 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001255 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001256 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001257 break;
1258
1259 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001260 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001261 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001262 break;
1263
1264 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001265 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001266 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001267 }
1268}
1269
Calin Juravle175dc732015-08-25 15:42:32 +01001270void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1271 DCHECK(location.IsRegister());
1272 __ LoadImmediate(location.AsRegister<Register>(), value);
1273}
1274
Calin Juravlee460d1d2015-09-29 04:52:17 +01001275void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1276 if (Primitive::Is64BitType(dst_type)) {
1277 Move64(dst, src);
1278 } else {
1279 Move32(dst, src);
1280 }
1281}
1282
1283void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1284 if (location.IsRegister()) {
1285 locations->AddTemp(location);
1286 } else if (location.IsRegisterPair()) {
1287 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1288 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1289 } else {
1290 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1291 }
1292}
1293
Calin Juravle175dc732015-08-25 15:42:32 +01001294void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1295 HInstruction* instruction,
1296 uint32_t dex_pc,
1297 SlowPathCode* slow_path) {
1298 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1299 instruction,
1300 dex_pc,
1301 slow_path);
1302}
1303
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001304void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1305 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001306 uint32_t dex_pc,
1307 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001308 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001309 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1310 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001311 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001312}
1313
David Brazdilfc6a86a2015-06-26 10:33:45 +00001314void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001315 DCHECK(!successor->IsExitBlock());
1316
1317 HBasicBlock* block = got->GetBlock();
1318 HInstruction* previous = got->GetPrevious();
1319
1320 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001321 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001322 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1323 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1324 return;
1325 }
1326
1327 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1328 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1329 }
1330 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001331 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001332 }
1333}
1334
David Brazdilfc6a86a2015-06-26 10:33:45 +00001335void LocationsBuilderARM::VisitGoto(HGoto* got) {
1336 got->SetLocations(nullptr);
1337}
1338
1339void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1340 HandleGoto(got, got->GetSuccessor());
1341}
1342
1343void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1344 try_boundary->SetLocations(nullptr);
1345}
1346
1347void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1348 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1349 if (!successor->IsExitBlock()) {
1350 HandleGoto(try_boundary, successor);
1351 }
1352}
1353
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001354void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001355 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001356}
1357
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001358void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001359}
1360
Roland Levillain4fa13f62015-07-06 18:11:54 +01001361void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1362 Label* true_label,
1363 Label* false_label) {
1364 __ vmstat(); // transfer FP status register to ARM APSR.
Aart Bike9f37602015-10-09 11:15:55 -07001365 // TODO: merge into a single branch (except "equal or unordered" and "not equal")
Roland Levillain4fa13f62015-07-06 18:11:54 +01001366 if (cond->IsFPConditionTrueIfNaN()) {
1367 __ b(true_label, VS); // VS for unordered.
1368 } else if (cond->IsFPConditionFalseIfNaN()) {
1369 __ b(false_label, VS); // VS for unordered.
1370 }
Aart Bike9f37602015-10-09 11:15:55 -07001371 __ b(true_label, ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001372}
1373
1374void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1375 Label* true_label,
1376 Label* false_label) {
1377 LocationSummary* locations = cond->GetLocations();
1378 Location left = locations->InAt(0);
1379 Location right = locations->InAt(1);
1380 IfCondition if_cond = cond->GetCondition();
1381
1382 Register left_high = left.AsRegisterPairHigh<Register>();
1383 Register left_low = left.AsRegisterPairLow<Register>();
1384 IfCondition true_high_cond = if_cond;
1385 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001386 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001387
1388 // Set the conditions for the test, remembering that == needs to be
1389 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001390 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001391 switch (if_cond) {
1392 case kCondEQ:
1393 case kCondNE:
1394 // Nothing to do.
1395 break;
1396 case kCondLT:
1397 false_high_cond = kCondGT;
1398 break;
1399 case kCondLE:
1400 true_high_cond = kCondLT;
1401 break;
1402 case kCondGT:
1403 false_high_cond = kCondLT;
1404 break;
1405 case kCondGE:
1406 true_high_cond = kCondGT;
1407 break;
Aart Bike9f37602015-10-09 11:15:55 -07001408 case kCondB:
1409 false_high_cond = kCondA;
1410 break;
1411 case kCondBE:
1412 true_high_cond = kCondB;
1413 break;
1414 case kCondA:
1415 false_high_cond = kCondB;
1416 break;
1417 case kCondAE:
1418 true_high_cond = kCondA;
1419 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001420 }
1421 if (right.IsConstant()) {
1422 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1423 int32_t val_low = Low32Bits(value);
1424 int32_t val_high = High32Bits(value);
1425
Vladimir Markoac6ac102015-12-17 12:14:00 +00001426 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001427 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001428 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001429 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001430 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001431 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001432 __ b(true_label, ARMCondition(true_high_cond));
1433 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001434 }
1435 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001436 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001437 } else {
1438 Register right_high = right.AsRegisterPairHigh<Register>();
1439 Register right_low = right.AsRegisterPairLow<Register>();
1440
1441 __ cmp(left_high, ShifterOperand(right_high));
1442 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001443 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001444 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001445 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001446 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001447 __ b(true_label, ARMCondition(true_high_cond));
1448 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001449 }
1450 // Must be equal high, so compare the lows.
1451 __ cmp(left_low, ShifterOperand(right_low));
1452 }
1453 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001454 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001455 __ b(true_label, final_condition);
1456}
1457
David Brazdil0debae72015-11-12 18:37:00 +00001458void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1459 Label* true_target_in,
1460 Label* false_target_in) {
1461 // Generated branching requires both targets to be explicit. If either of the
1462 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1463 Label fallthrough_target;
1464 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1465 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1466
Roland Levillain4fa13f62015-07-06 18:11:54 +01001467 LocationSummary* locations = condition->GetLocations();
1468 Location left = locations->InAt(0);
1469 Location right = locations->InAt(1);
1470
Roland Levillain4fa13f62015-07-06 18:11:54 +01001471 Primitive::Type type = condition->InputAt(0)->GetType();
1472 switch (type) {
1473 case Primitive::kPrimLong:
1474 GenerateLongComparesAndJumps(condition, true_target, false_target);
1475 break;
1476 case Primitive::kPrimFloat:
1477 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1478 GenerateFPJumps(condition, true_target, false_target);
1479 break;
1480 case Primitive::kPrimDouble:
1481 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1482 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1483 GenerateFPJumps(condition, true_target, false_target);
1484 break;
1485 default:
1486 LOG(FATAL) << "Unexpected compare type " << type;
1487 }
1488
David Brazdil0debae72015-11-12 18:37:00 +00001489 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001490 __ b(false_target);
1491 }
David Brazdil0debae72015-11-12 18:37:00 +00001492
1493 if (fallthrough_target.IsLinked()) {
1494 __ Bind(&fallthrough_target);
1495 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001496}
1497
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001498void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001499 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001500 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001501 Label* false_target) {
1502 HInstruction* cond = instruction->InputAt(condition_input_index);
1503
1504 if (true_target == nullptr && false_target == nullptr) {
1505 // Nothing to do. The code always falls through.
1506 return;
1507 } else if (cond->IsIntConstant()) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001508 // Constant condition, statically compared against 1.
David Brazdil0debae72015-11-12 18:37:00 +00001509 if (cond->AsIntConstant()->IsOne()) {
1510 if (true_target != nullptr) {
1511 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001512 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001513 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001514 DCHECK(cond->AsIntConstant()->IsZero());
1515 if (false_target != nullptr) {
1516 __ b(false_target);
1517 }
1518 }
1519 return;
1520 }
1521
1522 // The following code generates these patterns:
1523 // (1) true_target == nullptr && false_target != nullptr
1524 // - opposite condition true => branch to false_target
1525 // (2) true_target != nullptr && false_target == nullptr
1526 // - condition true => branch to true_target
1527 // (3) true_target != nullptr && false_target != nullptr
1528 // - condition true => branch to true_target
1529 // - branch to false_target
1530 if (IsBooleanValueOrMaterializedCondition(cond)) {
1531 // Condition has been materialized, compare the output to 0.
1532 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1533 DCHECK(cond_val.IsRegister());
1534 if (true_target == nullptr) {
1535 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1536 } else {
1537 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001538 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001539 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001540 // Condition has not been materialized. Use its inputs as the comparison and
1541 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001542 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001543
1544 // If this is a long or FP comparison that has been folded into
1545 // the HCondition, generate the comparison directly.
1546 Primitive::Type type = condition->InputAt(0)->GetType();
1547 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1548 GenerateCompareTestAndBranch(condition, true_target, false_target);
1549 return;
1550 }
1551
1552 LocationSummary* locations = cond->GetLocations();
1553 DCHECK(locations->InAt(0).IsRegister());
1554 Register left = locations->InAt(0).AsRegister<Register>();
1555 Location right = locations->InAt(1);
1556 if (right.IsRegister()) {
1557 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001558 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001559 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001560 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001561 }
1562 if (true_target == nullptr) {
1563 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1564 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001565 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001566 }
Dave Allison20dfc792014-06-16 20:44:29 -07001567 }
David Brazdil0debae72015-11-12 18:37:00 +00001568
1569 // If neither branch falls through (case 3), the conditional branch to `true_target`
1570 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1571 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001572 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001573 }
1574}
1575
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001576void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001577 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1578 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001579 locations->SetInAt(0, Location::RequiresRegister());
1580 }
1581}
1582
1583void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001584 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1585 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1586 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1587 nullptr : codegen_->GetLabelOf(true_successor);
1588 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1589 nullptr : codegen_->GetLabelOf(false_successor);
1590 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001591}
1592
1593void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1594 LocationSummary* locations = new (GetGraph()->GetArena())
1595 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001596 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001597 locations->SetInAt(0, Location::RequiresRegister());
1598 }
1599}
1600
1601void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
David Brazdil0debae72015-11-12 18:37:00 +00001602 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DeoptimizationSlowPathARM(deoptimize);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001603 codegen_->AddSlowPath(slow_path);
David Brazdil0debae72015-11-12 18:37:00 +00001604 GenerateTestAndBranch(deoptimize,
1605 /* condition_input_index */ 0,
1606 slow_path->GetEntryLabel(),
1607 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001608}
Dave Allison20dfc792014-06-16 20:44:29 -07001609
Roland Levillain0d37cd02015-05-27 16:39:19 +01001610void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001611 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001612 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001613 // Handle the long/FP comparisons made in instruction simplification.
1614 switch (cond->InputAt(0)->GetType()) {
1615 case Primitive::kPrimLong:
1616 locations->SetInAt(0, Location::RequiresRegister());
1617 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1618 if (cond->NeedsMaterialization()) {
1619 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1620 }
1621 break;
1622
1623 case Primitive::kPrimFloat:
1624 case Primitive::kPrimDouble:
1625 locations->SetInAt(0, Location::RequiresFpuRegister());
1626 locations->SetInAt(1, Location::RequiresFpuRegister());
1627 if (cond->NeedsMaterialization()) {
1628 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1629 }
1630 break;
1631
1632 default:
1633 locations->SetInAt(0, Location::RequiresRegister());
1634 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1635 if (cond->NeedsMaterialization()) {
1636 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1637 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001638 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001639}
1640
Roland Levillain0d37cd02015-05-27 16:39:19 +01001641void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001642 if (!cond->NeedsMaterialization()) {
1643 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001644 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001645
1646 LocationSummary* locations = cond->GetLocations();
1647 Location left = locations->InAt(0);
1648 Location right = locations->InAt(1);
1649 Register out = locations->Out().AsRegister<Register>();
1650 Label true_label, false_label;
1651
1652 switch (cond->InputAt(0)->GetType()) {
1653 default: {
1654 // Integer case.
1655 if (right.IsRegister()) {
1656 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1657 } else {
1658 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001659 __ CmpConstant(left.AsRegister<Register>(),
1660 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001661 }
Aart Bike9f37602015-10-09 11:15:55 -07001662 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001663 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001664 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001665 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001666 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001667 return;
1668 }
1669 case Primitive::kPrimLong:
1670 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1671 break;
1672 case Primitive::kPrimFloat:
1673 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1674 GenerateFPJumps(cond, &true_label, &false_label);
1675 break;
1676 case Primitive::kPrimDouble:
1677 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1678 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1679 GenerateFPJumps(cond, &true_label, &false_label);
1680 break;
1681 }
1682
1683 // Convert the jumps into the result.
1684 Label done_label;
1685
1686 // False case: result = 0.
1687 __ Bind(&false_label);
1688 __ LoadImmediate(out, 0);
1689 __ b(&done_label);
1690
1691 // True case: result = 1.
1692 __ Bind(&true_label);
1693 __ LoadImmediate(out, 1);
1694 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001695}
1696
1697void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1698 VisitCondition(comp);
1699}
1700
1701void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1702 VisitCondition(comp);
1703}
1704
1705void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1706 VisitCondition(comp);
1707}
1708
1709void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1710 VisitCondition(comp);
1711}
1712
1713void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1714 VisitCondition(comp);
1715}
1716
1717void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1718 VisitCondition(comp);
1719}
1720
1721void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1722 VisitCondition(comp);
1723}
1724
1725void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1726 VisitCondition(comp);
1727}
1728
1729void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1730 VisitCondition(comp);
1731}
1732
1733void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1734 VisitCondition(comp);
1735}
1736
1737void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1738 VisitCondition(comp);
1739}
1740
1741void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1742 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001743}
1744
Aart Bike9f37602015-10-09 11:15:55 -07001745void LocationsBuilderARM::VisitBelow(HBelow* comp) {
1746 VisitCondition(comp);
1747}
1748
1749void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
1750 VisitCondition(comp);
1751}
1752
1753void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1754 VisitCondition(comp);
1755}
1756
1757void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1758 VisitCondition(comp);
1759}
1760
1761void LocationsBuilderARM::VisitAbove(HAbove* comp) {
1762 VisitCondition(comp);
1763}
1764
1765void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
1766 VisitCondition(comp);
1767}
1768
1769void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1770 VisitCondition(comp);
1771}
1772
1773void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1774 VisitCondition(comp);
1775}
1776
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001777void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001778 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001779}
1780
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001781void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1782 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001783}
1784
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001785void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001786 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001787}
1788
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001789void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001790 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001791}
1792
1793void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001794 LocationSummary* locations =
1795 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001796 switch (store->InputAt(1)->GetType()) {
1797 case Primitive::kPrimBoolean:
1798 case Primitive::kPrimByte:
1799 case Primitive::kPrimChar:
1800 case Primitive::kPrimShort:
1801 case Primitive::kPrimInt:
1802 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001803 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001804 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1805 break;
1806
1807 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001808 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001809 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1810 break;
1811
1812 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001813 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001814 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001815}
1816
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001817void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001818}
1819
1820void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001821 LocationSummary* locations =
1822 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001823 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001824}
1825
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001826void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001827 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001828}
1829
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001830void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1831 LocationSummary* locations =
1832 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1833 locations->SetOut(Location::ConstantLocation(constant));
1834}
1835
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001836void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001837 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001838}
1839
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001840void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001841 LocationSummary* locations =
1842 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001843 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001844}
1845
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001846void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001847 // Will be generated at use site.
1848}
1849
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001850void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1851 LocationSummary* locations =
1852 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1853 locations->SetOut(Location::ConstantLocation(constant));
1854}
1855
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001856void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001857 // Will be generated at use site.
1858}
1859
1860void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1861 LocationSummary* locations =
1862 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1863 locations->SetOut(Location::ConstantLocation(constant));
1864}
1865
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001866void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001867 // Will be generated at use site.
1868}
1869
Calin Juravle27df7582015-04-17 19:12:31 +01001870void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1871 memory_barrier->SetLocations(nullptr);
1872}
1873
1874void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1875 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1876}
1877
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001878void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001879 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001880}
1881
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001882void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001883 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001884}
1885
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001886void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001887 LocationSummary* locations =
1888 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001889 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001890}
1891
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001892void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001893 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001894}
1895
Calin Juravle175dc732015-08-25 15:42:32 +01001896void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1897 // The trampoline uses the same calling convention as dex calling conventions,
1898 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1899 // the method_idx.
1900 HandleInvoke(invoke);
1901}
1902
1903void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1904 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1905}
1906
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001907void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001908 // When we do not run baseline, explicit clinit checks triggered by static
1909 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1910 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001911
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001912 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001913 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001914 codegen_->GetInstructionSetFeatures());
1915 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001916 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1917 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1918 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001919 return;
1920 }
1921
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001922 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001923
1924 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1925 if (invoke->HasPcRelativeDexCache()) {
1926 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1927 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001928}
1929
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001930static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1931 if (invoke->GetLocations()->Intrinsified()) {
1932 IntrinsicCodeGeneratorARM intrinsic(codegen);
1933 intrinsic.Dispatch(invoke);
1934 return true;
1935 }
1936 return false;
1937}
1938
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001939void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001940 // When we do not run baseline, explicit clinit checks triggered by static
1941 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1942 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001943
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001944 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1945 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001946 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001947
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001948 LocationSummary* locations = invoke->GetLocations();
1949 codegen_->GenerateStaticOrDirectCall(
1950 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001951 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001952}
1953
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001954void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001955 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001956 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001957}
1958
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001959void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001960 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001961 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001962 codegen_->GetInstructionSetFeatures());
1963 if (intrinsic.TryDispatch(invoke)) {
1964 return;
1965 }
1966
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001967 HandleInvoke(invoke);
1968}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001969
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001970void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001971 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1972 return;
1973 }
1974
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001975 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001976 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001977 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001978}
1979
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001980void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1981 HandleInvoke(invoke);
1982 // Add the hidden argument.
1983 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1984}
1985
1986void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1987 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001988 LocationSummary* locations = invoke->GetLocations();
1989 Register temp = locations->GetTemp(0).AsRegister<Register>();
1990 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001991 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1992 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001993 Location receiver = locations->InAt(0);
1994 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1995
Roland Levillain3b359c72015-11-17 19:35:12 +00001996 // Set the hidden argument. This is safe to do this here, as R12
1997 // won't be modified thereafter, before the `blx` (call) instruction.
1998 DCHECK_EQ(R12, hidden_reg);
1999 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002000
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002001 if (receiver.IsStackSlot()) {
2002 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00002003 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002004 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
2005 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00002006 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00002007 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002008 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002009 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00002010 // Instead of simply (possibly) unpoisoning `temp` here, we should
2011 // emit a read barrier for the previous class reference load.
2012 // However this is not required in practice, as this is an
2013 // intermediate/temporary reference and because the current
2014 // concurrent copying collector keeps the from-space memory
2015 // intact/accessible until the end of the marking phase (the
2016 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01002017 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002018 // temp = temp->GetImtEntryAt(method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00002019 uint32_t entry_point =
2020 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00002021 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
2022 // LR = temp->GetEntryPoint();
2023 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
2024 // LR();
2025 __ blx(LR);
2026 DCHECK(!codegen_->IsLeafMethod());
2027 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2028}
2029
Roland Levillain88cb1752014-10-20 16:36:47 +01002030void LocationsBuilderARM::VisitNeg(HNeg* neg) {
2031 LocationSummary* locations =
2032 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2033 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002034 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01002035 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2037 break;
2038 }
2039 case Primitive::kPrimLong: {
2040 locations->SetInAt(0, Location::RequiresRegister());
2041 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002042 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002043 }
Roland Levillain88cb1752014-10-20 16:36:47 +01002044
Roland Levillain88cb1752014-10-20 16:36:47 +01002045 case Primitive::kPrimFloat:
2046 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002047 locations->SetInAt(0, Location::RequiresFpuRegister());
2048 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01002049 break;
2050
2051 default:
2052 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2053 }
2054}
2055
2056void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2057 LocationSummary* locations = neg->GetLocations();
2058 Location out = locations->Out();
2059 Location in = locations->InAt(0);
2060 switch (neg->GetResultType()) {
2061 case Primitive::kPrimInt:
2062 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002063 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01002064 break;
2065
2066 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002067 DCHECK(in.IsRegisterPair());
2068 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2069 __ rsbs(out.AsRegisterPairLow<Register>(),
2070 in.AsRegisterPairLow<Register>(),
2071 ShifterOperand(0));
2072 // We cannot emit an RSC (Reverse Subtract with Carry)
2073 // instruction here, as it does not exist in the Thumb-2
2074 // instruction set. We use the following approach
2075 // using SBC and SUB instead.
2076 //
2077 // out.hi = -C
2078 __ sbc(out.AsRegisterPairHigh<Register>(),
2079 out.AsRegisterPairHigh<Register>(),
2080 ShifterOperand(out.AsRegisterPairHigh<Register>()));
2081 // out.hi = out.hi - in.hi
2082 __ sub(out.AsRegisterPairHigh<Register>(),
2083 out.AsRegisterPairHigh<Register>(),
2084 ShifterOperand(in.AsRegisterPairHigh<Register>()));
2085 break;
2086
Roland Levillain88cb1752014-10-20 16:36:47 +01002087 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002088 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002089 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002090 break;
2091
Roland Levillain88cb1752014-10-20 16:36:47 +01002092 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002093 DCHECK(in.IsFpuRegisterPair());
2094 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2095 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01002096 break;
2097
2098 default:
2099 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2100 }
2101}
2102
Roland Levillaindff1f282014-11-05 14:15:05 +00002103void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002104 Primitive::Type result_type = conversion->GetResultType();
2105 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002106 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002107
Roland Levillain5b3ee562015-04-14 16:02:41 +01002108 // The float-to-long, double-to-long and long-to-float type conversions
2109 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002110 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002111 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2112 && result_type == Primitive::kPrimLong)
2113 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002114 ? LocationSummary::kCall
2115 : LocationSummary::kNoCall;
2116 LocationSummary* locations =
2117 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2118
David Brazdilb2bd1c52015-03-25 11:17:37 +00002119 // The Java language does not allow treating boolean as an integral type but
2120 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002121
Roland Levillaindff1f282014-11-05 14:15:05 +00002122 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002123 case Primitive::kPrimByte:
2124 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002125 case Primitive::kPrimBoolean:
2126 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002127 case Primitive::kPrimShort:
2128 case Primitive::kPrimInt:
2129 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002130 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002131 locations->SetInAt(0, Location::RequiresRegister());
2132 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2133 break;
2134
2135 default:
2136 LOG(FATAL) << "Unexpected type conversion from " << input_type
2137 << " to " << result_type;
2138 }
2139 break;
2140
Roland Levillain01a8d712014-11-14 16:27:39 +00002141 case Primitive::kPrimShort:
2142 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002143 case Primitive::kPrimBoolean:
2144 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002145 case Primitive::kPrimByte:
2146 case Primitive::kPrimInt:
2147 case Primitive::kPrimChar:
2148 // Processing a Dex `int-to-short' instruction.
2149 locations->SetInAt(0, Location::RequiresRegister());
2150 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2151 break;
2152
2153 default:
2154 LOG(FATAL) << "Unexpected type conversion from " << input_type
2155 << " to " << result_type;
2156 }
2157 break;
2158
Roland Levillain946e1432014-11-11 17:35:19 +00002159 case Primitive::kPrimInt:
2160 switch (input_type) {
2161 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002162 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002163 locations->SetInAt(0, Location::Any());
2164 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2165 break;
2166
2167 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002168 // Processing a Dex `float-to-int' instruction.
2169 locations->SetInAt(0, Location::RequiresFpuRegister());
2170 locations->SetOut(Location::RequiresRegister());
2171 locations->AddTemp(Location::RequiresFpuRegister());
2172 break;
2173
Roland Levillain946e1432014-11-11 17:35:19 +00002174 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002175 // Processing a Dex `double-to-int' instruction.
2176 locations->SetInAt(0, Location::RequiresFpuRegister());
2177 locations->SetOut(Location::RequiresRegister());
2178 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002179 break;
2180
2181 default:
2182 LOG(FATAL) << "Unexpected type conversion from " << input_type
2183 << " to " << result_type;
2184 }
2185 break;
2186
Roland Levillaindff1f282014-11-05 14:15:05 +00002187 case Primitive::kPrimLong:
2188 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002189 case Primitive::kPrimBoolean:
2190 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002191 case Primitive::kPrimByte:
2192 case Primitive::kPrimShort:
2193 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002194 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002195 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002196 locations->SetInAt(0, Location::RequiresRegister());
2197 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2198 break;
2199
Roland Levillain624279f2014-12-04 11:54:28 +00002200 case Primitive::kPrimFloat: {
2201 // Processing a Dex `float-to-long' instruction.
2202 InvokeRuntimeCallingConvention calling_convention;
2203 locations->SetInAt(0, Location::FpuRegisterLocation(
2204 calling_convention.GetFpuRegisterAt(0)));
2205 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2206 break;
2207 }
2208
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002209 case Primitive::kPrimDouble: {
2210 // Processing a Dex `double-to-long' instruction.
2211 InvokeRuntimeCallingConvention calling_convention;
2212 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2213 calling_convention.GetFpuRegisterAt(0),
2214 calling_convention.GetFpuRegisterAt(1)));
2215 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002216 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002217 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002218
2219 default:
2220 LOG(FATAL) << "Unexpected type conversion from " << input_type
2221 << " to " << result_type;
2222 }
2223 break;
2224
Roland Levillain981e4542014-11-14 11:47:14 +00002225 case Primitive::kPrimChar:
2226 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002227 case Primitive::kPrimBoolean:
2228 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002229 case Primitive::kPrimByte:
2230 case Primitive::kPrimShort:
2231 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002232 // Processing a Dex `int-to-char' instruction.
2233 locations->SetInAt(0, Location::RequiresRegister());
2234 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2235 break;
2236
2237 default:
2238 LOG(FATAL) << "Unexpected type conversion from " << input_type
2239 << " to " << result_type;
2240 }
2241 break;
2242
Roland Levillaindff1f282014-11-05 14:15:05 +00002243 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002244 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002245 case Primitive::kPrimBoolean:
2246 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002247 case Primitive::kPrimByte:
2248 case Primitive::kPrimShort:
2249 case Primitive::kPrimInt:
2250 case Primitive::kPrimChar:
2251 // Processing a Dex `int-to-float' instruction.
2252 locations->SetInAt(0, Location::RequiresRegister());
2253 locations->SetOut(Location::RequiresFpuRegister());
2254 break;
2255
Roland Levillain5b3ee562015-04-14 16:02:41 +01002256 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002257 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002258 InvokeRuntimeCallingConvention calling_convention;
2259 locations->SetInAt(0, Location::RegisterPairLocation(
2260 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2261 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002262 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002263 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002264
Roland Levillaincff13742014-11-17 14:32:17 +00002265 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002266 // Processing a Dex `double-to-float' instruction.
2267 locations->SetInAt(0, Location::RequiresFpuRegister());
2268 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002269 break;
2270
2271 default:
2272 LOG(FATAL) << "Unexpected type conversion from " << input_type
2273 << " to " << result_type;
2274 };
2275 break;
2276
Roland Levillaindff1f282014-11-05 14:15:05 +00002277 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002278 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002279 case Primitive::kPrimBoolean:
2280 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002281 case Primitive::kPrimByte:
2282 case Primitive::kPrimShort:
2283 case Primitive::kPrimInt:
2284 case Primitive::kPrimChar:
2285 // Processing a Dex `int-to-double' instruction.
2286 locations->SetInAt(0, Location::RequiresRegister());
2287 locations->SetOut(Location::RequiresFpuRegister());
2288 break;
2289
2290 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002291 // Processing a Dex `long-to-double' instruction.
2292 locations->SetInAt(0, Location::RequiresRegister());
2293 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002294 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002295 locations->AddTemp(Location::RequiresFpuRegister());
2296 break;
2297
Roland Levillaincff13742014-11-17 14:32:17 +00002298 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002299 // Processing a Dex `float-to-double' instruction.
2300 locations->SetInAt(0, Location::RequiresFpuRegister());
2301 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002302 break;
2303
2304 default:
2305 LOG(FATAL) << "Unexpected type conversion from " << input_type
2306 << " to " << result_type;
2307 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002308 break;
2309
2310 default:
2311 LOG(FATAL) << "Unexpected type conversion from " << input_type
2312 << " to " << result_type;
2313 }
2314}
2315
2316void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2317 LocationSummary* locations = conversion->GetLocations();
2318 Location out = locations->Out();
2319 Location in = locations->InAt(0);
2320 Primitive::Type result_type = conversion->GetResultType();
2321 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002322 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002323 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002324 case Primitive::kPrimByte:
2325 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002326 case Primitive::kPrimBoolean:
2327 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002328 case Primitive::kPrimShort:
2329 case Primitive::kPrimInt:
2330 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002331 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002332 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002333 break;
2334
2335 default:
2336 LOG(FATAL) << "Unexpected type conversion from " << input_type
2337 << " to " << result_type;
2338 }
2339 break;
2340
Roland Levillain01a8d712014-11-14 16:27:39 +00002341 case Primitive::kPrimShort:
2342 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002343 case Primitive::kPrimBoolean:
2344 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002345 case Primitive::kPrimByte:
2346 case Primitive::kPrimInt:
2347 case Primitive::kPrimChar:
2348 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002349 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002350 break;
2351
2352 default:
2353 LOG(FATAL) << "Unexpected type conversion from " << input_type
2354 << " to " << result_type;
2355 }
2356 break;
2357
Roland Levillain946e1432014-11-11 17:35:19 +00002358 case Primitive::kPrimInt:
2359 switch (input_type) {
2360 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002361 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002362 DCHECK(out.IsRegister());
2363 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002364 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002365 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002366 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002367 } else {
2368 DCHECK(in.IsConstant());
2369 DCHECK(in.GetConstant()->IsLongConstant());
2370 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002371 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002372 }
2373 break;
2374
Roland Levillain3f8f9362014-12-02 17:45:01 +00002375 case Primitive::kPrimFloat: {
2376 // Processing a Dex `float-to-int' instruction.
2377 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2378 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2379 __ vcvtis(temp, temp);
2380 __ vmovrs(out.AsRegister<Register>(), temp);
2381 break;
2382 }
2383
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002384 case Primitive::kPrimDouble: {
2385 // Processing a Dex `double-to-int' instruction.
2386 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2387 DRegister temp_d = FromLowSToD(temp_s);
2388 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2389 __ vcvtid(temp_s, temp_d);
2390 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002391 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002392 }
Roland Levillain946e1432014-11-11 17:35:19 +00002393
2394 default:
2395 LOG(FATAL) << "Unexpected type conversion from " << input_type
2396 << " to " << result_type;
2397 }
2398 break;
2399
Roland Levillaindff1f282014-11-05 14:15:05 +00002400 case Primitive::kPrimLong:
2401 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002402 case Primitive::kPrimBoolean:
2403 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002404 case Primitive::kPrimByte:
2405 case Primitive::kPrimShort:
2406 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002407 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002408 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002409 DCHECK(out.IsRegisterPair());
2410 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002411 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002412 // Sign extension.
2413 __ Asr(out.AsRegisterPairHigh<Register>(),
2414 out.AsRegisterPairLow<Register>(),
2415 31);
2416 break;
2417
2418 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002419 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002420 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2421 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002422 conversion->GetDexPc(),
2423 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002424 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002425 break;
2426
Roland Levillaindff1f282014-11-05 14:15:05 +00002427 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002428 // Processing a Dex `double-to-long' instruction.
2429 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2430 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002431 conversion->GetDexPc(),
2432 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002433 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002434 break;
2435
2436 default:
2437 LOG(FATAL) << "Unexpected type conversion from " << input_type
2438 << " to " << result_type;
2439 }
2440 break;
2441
Roland Levillain981e4542014-11-14 11:47:14 +00002442 case Primitive::kPrimChar:
2443 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002444 case Primitive::kPrimBoolean:
2445 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002446 case Primitive::kPrimByte:
2447 case Primitive::kPrimShort:
2448 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002449 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002450 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002451 break;
2452
2453 default:
2454 LOG(FATAL) << "Unexpected type conversion from " << input_type
2455 << " to " << result_type;
2456 }
2457 break;
2458
Roland Levillaindff1f282014-11-05 14:15:05 +00002459 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002460 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002461 case Primitive::kPrimBoolean:
2462 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002463 case Primitive::kPrimByte:
2464 case Primitive::kPrimShort:
2465 case Primitive::kPrimInt:
2466 case Primitive::kPrimChar: {
2467 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002468 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2469 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002470 break;
2471 }
2472
Roland Levillain5b3ee562015-04-14 16:02:41 +01002473 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002474 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002475 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2476 conversion,
2477 conversion->GetDexPc(),
2478 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002479 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002480 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002481
Roland Levillaincff13742014-11-17 14:32:17 +00002482 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002483 // Processing a Dex `double-to-float' instruction.
2484 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2485 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002486 break;
2487
2488 default:
2489 LOG(FATAL) << "Unexpected type conversion from " << input_type
2490 << " to " << result_type;
2491 };
2492 break;
2493
Roland Levillaindff1f282014-11-05 14:15:05 +00002494 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002495 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002496 case Primitive::kPrimBoolean:
2497 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002498 case Primitive::kPrimByte:
2499 case Primitive::kPrimShort:
2500 case Primitive::kPrimInt:
2501 case Primitive::kPrimChar: {
2502 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002503 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002504 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2505 out.AsFpuRegisterPairLow<SRegister>());
2506 break;
2507 }
2508
Roland Levillain647b9ed2014-11-27 12:06:00 +00002509 case Primitive::kPrimLong: {
2510 // Processing a Dex `long-to-double' instruction.
2511 Register low = in.AsRegisterPairLow<Register>();
2512 Register high = in.AsRegisterPairHigh<Register>();
2513 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2514 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002515 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002516 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002517 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2518 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002519
Roland Levillain682393c2015-04-14 15:57:52 +01002520 // temp_d = int-to-double(high)
2521 __ vmovsr(temp_s, high);
2522 __ vcvtdi(temp_d, temp_s);
2523 // constant_d = k2Pow32EncodingForDouble
2524 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2525 // out_d = unsigned-to-double(low)
2526 __ vmovsr(out_s, low);
2527 __ vcvtdu(out_d, out_s);
2528 // out_d += temp_d * constant_d
2529 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002530 break;
2531 }
2532
Roland Levillaincff13742014-11-17 14:32:17 +00002533 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002534 // Processing a Dex `float-to-double' instruction.
2535 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2536 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002537 break;
2538
2539 default:
2540 LOG(FATAL) << "Unexpected type conversion from " << input_type
2541 << " to " << result_type;
2542 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002543 break;
2544
2545 default:
2546 LOG(FATAL) << "Unexpected type conversion from " << input_type
2547 << " to " << result_type;
2548 }
2549}
2550
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002551void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002552 LocationSummary* locations =
2553 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002554 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002555 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002556 locations->SetInAt(0, Location::RequiresRegister());
2557 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002558 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2559 break;
2560 }
2561
2562 case Primitive::kPrimLong: {
2563 locations->SetInAt(0, Location::RequiresRegister());
2564 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002565 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002566 break;
2567 }
2568
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002569 case Primitive::kPrimFloat:
2570 case Primitive::kPrimDouble: {
2571 locations->SetInAt(0, Location::RequiresFpuRegister());
2572 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002573 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002574 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002575 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002576
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002577 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002578 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002579 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002580}
2581
2582void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2583 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002584 Location out = locations->Out();
2585 Location first = locations->InAt(0);
2586 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002587 switch (add->GetResultType()) {
2588 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002589 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002590 __ add(out.AsRegister<Register>(),
2591 first.AsRegister<Register>(),
2592 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002593 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002594 __ AddConstant(out.AsRegister<Register>(),
2595 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002596 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002597 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002598 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002599
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002600 case Primitive::kPrimLong: {
2601 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002602 __ adds(out.AsRegisterPairLow<Register>(),
2603 first.AsRegisterPairLow<Register>(),
2604 ShifterOperand(second.AsRegisterPairLow<Register>()));
2605 __ adc(out.AsRegisterPairHigh<Register>(),
2606 first.AsRegisterPairHigh<Register>(),
2607 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002608 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002609 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002610
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002611 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002612 __ vadds(out.AsFpuRegister<SRegister>(),
2613 first.AsFpuRegister<SRegister>(),
2614 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002615 break;
2616
2617 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002618 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2619 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2620 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002621 break;
2622
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002623 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002624 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002625 }
2626}
2627
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002628void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002629 LocationSummary* locations =
2630 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002631 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002632 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002633 locations->SetInAt(0, Location::RequiresRegister());
2634 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002635 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2636 break;
2637 }
2638
2639 case Primitive::kPrimLong: {
2640 locations->SetInAt(0, Location::RequiresRegister());
2641 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002642 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002643 break;
2644 }
Calin Juravle11351682014-10-23 15:38:15 +01002645 case Primitive::kPrimFloat:
2646 case Primitive::kPrimDouble: {
2647 locations->SetInAt(0, Location::RequiresFpuRegister());
2648 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002649 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002650 break;
Calin Juravle11351682014-10-23 15:38:15 +01002651 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002652 default:
Calin Juravle11351682014-10-23 15:38:15 +01002653 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002654 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002655}
2656
2657void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2658 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002659 Location out = locations->Out();
2660 Location first = locations->InAt(0);
2661 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002662 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002663 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002664 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002665 __ sub(out.AsRegister<Register>(),
2666 first.AsRegister<Register>(),
2667 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002668 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002669 __ AddConstant(out.AsRegister<Register>(),
2670 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002671 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002672 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002673 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002674 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002675
Calin Juravle11351682014-10-23 15:38:15 +01002676 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002677 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002678 __ subs(out.AsRegisterPairLow<Register>(),
2679 first.AsRegisterPairLow<Register>(),
2680 ShifterOperand(second.AsRegisterPairLow<Register>()));
2681 __ sbc(out.AsRegisterPairHigh<Register>(),
2682 first.AsRegisterPairHigh<Register>(),
2683 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002684 break;
Calin Juravle11351682014-10-23 15:38:15 +01002685 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002686
Calin Juravle11351682014-10-23 15:38:15 +01002687 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002688 __ vsubs(out.AsFpuRegister<SRegister>(),
2689 first.AsFpuRegister<SRegister>(),
2690 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002691 break;
Calin Juravle11351682014-10-23 15:38:15 +01002692 }
2693
2694 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002695 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2696 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2697 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002698 break;
2699 }
2700
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002701
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002702 default:
Calin Juravle11351682014-10-23 15:38:15 +01002703 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002704 }
2705}
2706
Calin Juravle34bacdf2014-10-07 20:23:36 +01002707void LocationsBuilderARM::VisitMul(HMul* mul) {
2708 LocationSummary* locations =
2709 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2710 switch (mul->GetResultType()) {
2711 case Primitive::kPrimInt:
2712 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002713 locations->SetInAt(0, Location::RequiresRegister());
2714 locations->SetInAt(1, Location::RequiresRegister());
2715 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002716 break;
2717 }
2718
Calin Juravleb5bfa962014-10-21 18:02:24 +01002719 case Primitive::kPrimFloat:
2720 case Primitive::kPrimDouble: {
2721 locations->SetInAt(0, Location::RequiresFpuRegister());
2722 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002723 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002724 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002725 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002726
2727 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002728 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002729 }
2730}
2731
2732void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2733 LocationSummary* locations = mul->GetLocations();
2734 Location out = locations->Out();
2735 Location first = locations->InAt(0);
2736 Location second = locations->InAt(1);
2737 switch (mul->GetResultType()) {
2738 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002739 __ mul(out.AsRegister<Register>(),
2740 first.AsRegister<Register>(),
2741 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002742 break;
2743 }
2744 case Primitive::kPrimLong: {
2745 Register out_hi = out.AsRegisterPairHigh<Register>();
2746 Register out_lo = out.AsRegisterPairLow<Register>();
2747 Register in1_hi = first.AsRegisterPairHigh<Register>();
2748 Register in1_lo = first.AsRegisterPairLow<Register>();
2749 Register in2_hi = second.AsRegisterPairHigh<Register>();
2750 Register in2_lo = second.AsRegisterPairLow<Register>();
2751
2752 // Extra checks to protect caused by the existence of R1_R2.
2753 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2754 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2755 DCHECK_NE(out_hi, in1_lo);
2756 DCHECK_NE(out_hi, in2_lo);
2757
2758 // input: in1 - 64 bits, in2 - 64 bits
2759 // output: out
2760 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2761 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2762 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2763
2764 // IP <- in1.lo * in2.hi
2765 __ mul(IP, in1_lo, in2_hi);
2766 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2767 __ mla(out_hi, in1_hi, in2_lo, IP);
2768 // out.lo <- (in1.lo * in2.lo)[31:0];
2769 __ umull(out_lo, IP, in1_lo, in2_lo);
2770 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2771 __ add(out_hi, out_hi, ShifterOperand(IP));
2772 break;
2773 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002774
2775 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002776 __ vmuls(out.AsFpuRegister<SRegister>(),
2777 first.AsFpuRegister<SRegister>(),
2778 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002779 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002780 }
2781
2782 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002783 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2784 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2785 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002786 break;
2787 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002788
2789 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002790 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002791 }
2792}
2793
Zheng Xuc6667102015-05-15 16:08:45 +08002794void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2795 DCHECK(instruction->IsDiv() || instruction->IsRem());
2796 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2797
2798 LocationSummary* locations = instruction->GetLocations();
2799 Location second = locations->InAt(1);
2800 DCHECK(second.IsConstant());
2801
2802 Register out = locations->Out().AsRegister<Register>();
2803 Register dividend = locations->InAt(0).AsRegister<Register>();
2804 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2805 DCHECK(imm == 1 || imm == -1);
2806
2807 if (instruction->IsRem()) {
2808 __ LoadImmediate(out, 0);
2809 } else {
2810 if (imm == 1) {
2811 __ Mov(out, dividend);
2812 } else {
2813 __ rsb(out, dividend, ShifterOperand(0));
2814 }
2815 }
2816}
2817
2818void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2819 DCHECK(instruction->IsDiv() || instruction->IsRem());
2820 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2821
2822 LocationSummary* locations = instruction->GetLocations();
2823 Location second = locations->InAt(1);
2824 DCHECK(second.IsConstant());
2825
2826 Register out = locations->Out().AsRegister<Register>();
2827 Register dividend = locations->InAt(0).AsRegister<Register>();
2828 Register temp = locations->GetTemp(0).AsRegister<Register>();
2829 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002830 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002831 DCHECK(IsPowerOfTwo(abs_imm));
2832 int ctz_imm = CTZ(abs_imm);
2833
2834 if (ctz_imm == 1) {
2835 __ Lsr(temp, dividend, 32 - ctz_imm);
2836 } else {
2837 __ Asr(temp, dividend, 31);
2838 __ Lsr(temp, temp, 32 - ctz_imm);
2839 }
2840 __ add(out, temp, ShifterOperand(dividend));
2841
2842 if (instruction->IsDiv()) {
2843 __ Asr(out, out, ctz_imm);
2844 if (imm < 0) {
2845 __ rsb(out, out, ShifterOperand(0));
2846 }
2847 } else {
2848 __ ubfx(out, out, 0, ctz_imm);
2849 __ sub(out, out, ShifterOperand(temp));
2850 }
2851}
2852
2853void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2854 DCHECK(instruction->IsDiv() || instruction->IsRem());
2855 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2856
2857 LocationSummary* locations = instruction->GetLocations();
2858 Location second = locations->InAt(1);
2859 DCHECK(second.IsConstant());
2860
2861 Register out = locations->Out().AsRegister<Register>();
2862 Register dividend = locations->InAt(0).AsRegister<Register>();
2863 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2864 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2865 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2866
2867 int64_t magic;
2868 int shift;
2869 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2870
2871 __ LoadImmediate(temp1, magic);
2872 __ smull(temp2, temp1, dividend, temp1);
2873
2874 if (imm > 0 && magic < 0) {
2875 __ add(temp1, temp1, ShifterOperand(dividend));
2876 } else if (imm < 0 && magic > 0) {
2877 __ sub(temp1, temp1, ShifterOperand(dividend));
2878 }
2879
2880 if (shift != 0) {
2881 __ Asr(temp1, temp1, shift);
2882 }
2883
2884 if (instruction->IsDiv()) {
2885 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2886 } else {
2887 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2888 // TODO: Strength reduction for mls.
2889 __ LoadImmediate(temp2, imm);
2890 __ mls(out, temp1, temp2, dividend);
2891 }
2892}
2893
2894void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2895 DCHECK(instruction->IsDiv() || instruction->IsRem());
2896 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2897
2898 LocationSummary* locations = instruction->GetLocations();
2899 Location second = locations->InAt(1);
2900 DCHECK(second.IsConstant());
2901
2902 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2903 if (imm == 0) {
2904 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2905 } else if (imm == 1 || imm == -1) {
2906 DivRemOneOrMinusOne(instruction);
2907 } else if (IsPowerOfTwo(std::abs(imm))) {
2908 DivRemByPowerOfTwo(instruction);
2909 } else {
2910 DCHECK(imm <= -2 || imm >= 2);
2911 GenerateDivRemWithAnyConstant(instruction);
2912 }
2913}
2914
Calin Juravle7c4954d2014-10-28 16:57:40 +00002915void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002916 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2917 if (div->GetResultType() == Primitive::kPrimLong) {
2918 // pLdiv runtime call.
2919 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002920 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2921 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002922 } else if (div->GetResultType() == Primitive::kPrimInt &&
2923 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2924 // pIdivmod runtime call.
2925 call_kind = LocationSummary::kCall;
2926 }
2927
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002928 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2929
Calin Juravle7c4954d2014-10-28 16:57:40 +00002930 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002931 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002932 if (div->InputAt(1)->IsConstant()) {
2933 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002934 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002935 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2936 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2937 if (abs_imm <= 1) {
2938 // No temp register required.
2939 } else {
2940 locations->AddTemp(Location::RequiresRegister());
2941 if (!IsPowerOfTwo(abs_imm)) {
2942 locations->AddTemp(Location::RequiresRegister());
2943 }
2944 }
2945 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002946 locations->SetInAt(0, Location::RequiresRegister());
2947 locations->SetInAt(1, Location::RequiresRegister());
2948 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2949 } else {
2950 InvokeRuntimeCallingConvention calling_convention;
2951 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2952 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2953 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2954 // we only need the former.
2955 locations->SetOut(Location::RegisterLocation(R0));
2956 }
Calin Juravled0d48522014-11-04 16:40:20 +00002957 break;
2958 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002959 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002960 InvokeRuntimeCallingConvention calling_convention;
2961 locations->SetInAt(0, Location::RegisterPairLocation(
2962 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2963 locations->SetInAt(1, Location::RegisterPairLocation(
2964 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002965 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002966 break;
2967 }
2968 case Primitive::kPrimFloat:
2969 case Primitive::kPrimDouble: {
2970 locations->SetInAt(0, Location::RequiresFpuRegister());
2971 locations->SetInAt(1, Location::RequiresFpuRegister());
2972 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2973 break;
2974 }
2975
2976 default:
2977 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2978 }
2979}
2980
2981void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2982 LocationSummary* locations = div->GetLocations();
2983 Location out = locations->Out();
2984 Location first = locations->InAt(0);
2985 Location second = locations->InAt(1);
2986
2987 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002988 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002989 if (second.IsConstant()) {
2990 GenerateDivRemConstantIntegral(div);
2991 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002992 __ sdiv(out.AsRegister<Register>(),
2993 first.AsRegister<Register>(),
2994 second.AsRegister<Register>());
2995 } else {
2996 InvokeRuntimeCallingConvention calling_convention;
2997 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2998 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2999 DCHECK_EQ(R0, out.AsRegister<Register>());
3000
3001 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003002 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003003 }
Calin Juravled0d48522014-11-04 16:40:20 +00003004 break;
3005 }
3006
Calin Juravle7c4954d2014-10-28 16:57:40 +00003007 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003008 InvokeRuntimeCallingConvention calling_convention;
3009 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3010 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3011 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3012 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3013 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003014 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003015
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003016 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003017 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00003018 break;
3019 }
3020
3021 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003022 __ vdivs(out.AsFpuRegister<SRegister>(),
3023 first.AsFpuRegister<SRegister>(),
3024 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003025 break;
3026 }
3027
3028 case Primitive::kPrimDouble: {
3029 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3030 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3031 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
3032 break;
3033 }
3034
3035 default:
3036 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3037 }
3038}
3039
Calin Juravlebacfec32014-11-14 15:54:36 +00003040void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003041 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003042
3043 // Most remainders are implemented in the runtime.
3044 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08003045 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3046 // sdiv will be replaced by other instruction sequence.
3047 call_kind = LocationSummary::kNoCall;
3048 } else if ((rem->GetResultType() == Primitive::kPrimInt)
3049 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003050 // Have hardware divide instruction for int, do it with three instructions.
3051 call_kind = LocationSummary::kNoCall;
3052 }
3053
Calin Juravlebacfec32014-11-14 15:54:36 +00003054 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3055
Calin Juravled2ec87d2014-12-08 14:24:46 +00003056 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003057 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003058 if (rem->InputAt(1)->IsConstant()) {
3059 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003060 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003061 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3062 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
3063 if (abs_imm <= 1) {
3064 // No temp register required.
3065 } else {
3066 locations->AddTemp(Location::RequiresRegister());
3067 if (!IsPowerOfTwo(abs_imm)) {
3068 locations->AddTemp(Location::RequiresRegister());
3069 }
3070 }
3071 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003072 locations->SetInAt(0, Location::RequiresRegister());
3073 locations->SetInAt(1, Location::RequiresRegister());
3074 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3075 locations->AddTemp(Location::RequiresRegister());
3076 } else {
3077 InvokeRuntimeCallingConvention calling_convention;
3078 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3079 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3080 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3081 // we only need the latter.
3082 locations->SetOut(Location::RegisterLocation(R1));
3083 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003084 break;
3085 }
3086 case Primitive::kPrimLong: {
3087 InvokeRuntimeCallingConvention calling_convention;
3088 locations->SetInAt(0, Location::RegisterPairLocation(
3089 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3090 locations->SetInAt(1, Location::RegisterPairLocation(
3091 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3092 // The runtime helper puts the output in R2,R3.
3093 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3094 break;
3095 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003096 case Primitive::kPrimFloat: {
3097 InvokeRuntimeCallingConvention calling_convention;
3098 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3099 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3100 locations->SetOut(Location::FpuRegisterLocation(S0));
3101 break;
3102 }
3103
Calin Juravlebacfec32014-11-14 15:54:36 +00003104 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003105 InvokeRuntimeCallingConvention calling_convention;
3106 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3107 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3108 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3109 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3110 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003111 break;
3112 }
3113
3114 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003115 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003116 }
3117}
3118
3119void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3120 LocationSummary* locations = rem->GetLocations();
3121 Location out = locations->Out();
3122 Location first = locations->InAt(0);
3123 Location second = locations->InAt(1);
3124
Calin Juravled2ec87d2014-12-08 14:24:46 +00003125 Primitive::Type type = rem->GetResultType();
3126 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003127 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003128 if (second.IsConstant()) {
3129 GenerateDivRemConstantIntegral(rem);
3130 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003131 Register reg1 = first.AsRegister<Register>();
3132 Register reg2 = second.AsRegister<Register>();
3133 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003134
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003135 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003136 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003137 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003138 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003139 } else {
3140 InvokeRuntimeCallingConvention calling_convention;
3141 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3142 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3143 DCHECK_EQ(R1, out.AsRegister<Register>());
3144
3145 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003146 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003147 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003148 break;
3149 }
3150
3151 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003152 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003153 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003154 break;
3155 }
3156
Calin Juravled2ec87d2014-12-08 14:24:46 +00003157 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003158 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003159 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003160 break;
3161 }
3162
Calin Juravlebacfec32014-11-14 15:54:36 +00003163 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003164 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003165 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003166 break;
3167 }
3168
3169 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003170 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003171 }
3172}
3173
Calin Juravled0d48522014-11-04 16:40:20 +00003174void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003175 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3176 ? LocationSummary::kCallOnSlowPath
3177 : LocationSummary::kNoCall;
3178 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003179 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003180 if (instruction->HasUses()) {
3181 locations->SetOut(Location::SameAsFirstInput());
3182 }
3183}
3184
3185void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003186 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003187 codegen_->AddSlowPath(slow_path);
3188
3189 LocationSummary* locations = instruction->GetLocations();
3190 Location value = locations->InAt(0);
3191
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003192 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003193 case Primitive::kPrimByte:
3194 case Primitive::kPrimChar:
3195 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003196 case Primitive::kPrimInt: {
3197 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003198 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003199 } else {
3200 DCHECK(value.IsConstant()) << value;
3201 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3202 __ b(slow_path->GetEntryLabel());
3203 }
3204 }
3205 break;
3206 }
3207 case Primitive::kPrimLong: {
3208 if (value.IsRegisterPair()) {
3209 __ orrs(IP,
3210 value.AsRegisterPairLow<Register>(),
3211 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3212 __ b(slow_path->GetEntryLabel(), EQ);
3213 } else {
3214 DCHECK(value.IsConstant()) << value;
3215 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3216 __ b(slow_path->GetEntryLabel());
3217 }
3218 }
3219 break;
3220 default:
3221 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3222 }
3223 }
Calin Juravled0d48522014-11-04 16:40:20 +00003224}
3225
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003226void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3227 Register in = locations->InAt(0).AsRegister<Register>();
3228 Location rhs = locations->InAt(1);
3229 Register out = locations->Out().AsRegister<Register>();
3230
3231 if (rhs.IsConstant()) {
3232 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3233 // so map all rotations to a +ve. equivalent in that range.
3234 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3235 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3236 if (rot) {
3237 // Rotate, mapping left rotations to right equivalents if necessary.
3238 // (e.g. left by 2 bits == right by 30.)
3239 __ Ror(out, in, rot);
3240 } else if (out != in) {
3241 __ Mov(out, in);
3242 }
3243 } else {
3244 __ Ror(out, in, rhs.AsRegister<Register>());
3245 }
3246}
3247
3248// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3249// rotates by swapping input regs (effectively rotating by the first 32-bits of
3250// a larger rotation) or flipping direction (thus treating larger right/left
3251// rotations as sub-word sized rotations in the other direction) as appropriate.
3252void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3253 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3254 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3255 Location rhs = locations->InAt(1);
3256 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3257 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3258
3259 if (rhs.IsConstant()) {
3260 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3261 // Map all rotations to +ve. equivalents on the interval [0,63].
3262 rot &= kMaxLongShiftValue;
3263 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3264 // logic below to a simple pair of binary orr.
3265 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3266 if (rot >= kArmBitsPerWord) {
3267 rot -= kArmBitsPerWord;
3268 std::swap(in_reg_hi, in_reg_lo);
3269 }
3270 // Rotate, or mov to out for zero or word size rotations.
3271 if (rot != 0u) {
3272 __ Lsr(out_reg_hi, in_reg_hi, rot);
3273 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3274 __ Lsr(out_reg_lo, in_reg_lo, rot);
3275 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3276 } else {
3277 __ Mov(out_reg_lo, in_reg_lo);
3278 __ Mov(out_reg_hi, in_reg_hi);
3279 }
3280 } else {
3281 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3282 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3283 Label end;
3284 Label shift_by_32_plus_shift_right;
3285
3286 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3287 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3288 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3289 __ b(&shift_by_32_plus_shift_right, CC);
3290
3291 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3292 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3293 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3294 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3295 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3296 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3297 __ Lsr(shift_left, in_reg_hi, shift_right);
3298 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3299 __ b(&end);
3300
3301 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3302 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3303 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3304 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3305 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3306 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3307 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3308 __ Lsl(shift_right, in_reg_hi, shift_left);
3309 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3310
3311 __ Bind(&end);
3312 }
3313}
3314void LocationsBuilderARM::HandleRotate(HRor* ror) {
3315 LocationSummary* locations =
3316 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3317 switch (ror->GetResultType()) {
3318 case Primitive::kPrimInt: {
3319 locations->SetInAt(0, Location::RequiresRegister());
3320 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3321 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3322 break;
3323 }
3324 case Primitive::kPrimLong: {
3325 locations->SetInAt(0, Location::RequiresRegister());
3326 if (ror->InputAt(1)->IsConstant()) {
3327 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3328 } else {
3329 locations->SetInAt(1, Location::RequiresRegister());
3330 locations->AddTemp(Location::RequiresRegister());
3331 locations->AddTemp(Location::RequiresRegister());
3332 }
3333 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3334 break;
3335 }
3336 default:
3337 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3338 }
3339}
3340
3341void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) {
3342 LocationSummary* locations = ror->GetLocations();
3343 Primitive::Type type = ror->GetResultType();
3344 switch (type) {
3345 case Primitive::kPrimInt: {
3346 HandleIntegerRotate(locations);
3347 break;
3348 }
3349 case Primitive::kPrimLong: {
3350 HandleLongRotate(locations);
3351 break;
3352 }
3353 default:
3354 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003355 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003356 }
3357}
3358
3359void LocationsBuilderARM::VisitRor(HRor* op) {
Vladimir Marko351dddf2015-12-11 16:34:46 +00003360 HandleRotate(op);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003361}
3362
3363void InstructionCodeGeneratorARM::VisitRor(HRor* op) {
Vladimir Marko351dddf2015-12-11 16:34:46 +00003364 HandleRotate(op);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003365}
3366
Calin Juravle9aec02f2014-11-18 23:06:35 +00003367void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3368 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3369
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003370 LocationSummary* locations =
3371 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003372
3373 switch (op->GetResultType()) {
3374 case Primitive::kPrimInt: {
3375 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003376 if (op->InputAt(1)->IsConstant()) {
3377 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3378 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3379 } else {
3380 locations->SetInAt(1, Location::RequiresRegister());
3381 // Make the output overlap, as it will be used to hold the masked
3382 // second input.
3383 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3384 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003385 break;
3386 }
3387 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003388 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003389 if (op->InputAt(1)->IsConstant()) {
3390 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3391 // For simplicity, use kOutputOverlap even though we only require that low registers
3392 // don't clash with high registers which the register allocator currently guarantees.
3393 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3394 } else {
3395 locations->SetInAt(1, Location::RequiresRegister());
3396 locations->AddTemp(Location::RequiresRegister());
3397 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3398 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003399 break;
3400 }
3401 default:
3402 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3403 }
3404}
3405
3406void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3407 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3408
3409 LocationSummary* locations = op->GetLocations();
3410 Location out = locations->Out();
3411 Location first = locations->InAt(0);
3412 Location second = locations->InAt(1);
3413
3414 Primitive::Type type = op->GetResultType();
3415 switch (type) {
3416 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003417 Register out_reg = out.AsRegister<Register>();
3418 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003419 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003420 Register second_reg = second.AsRegister<Register>();
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003421 // Arm doesn't mask the shift count so we need to do it ourselves.
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003422 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003423 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003424 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003425 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003426 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003427 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003428 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003429 }
3430 } else {
3431 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3432 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
3433 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
3434 __ Mov(out_reg, first_reg);
3435 } else if (op->IsShl()) {
3436 __ Lsl(out_reg, first_reg, shift_value);
3437 } else if (op->IsShr()) {
3438 __ Asr(out_reg, first_reg, shift_value);
3439 } else {
3440 __ Lsr(out_reg, first_reg, shift_value);
3441 }
3442 }
3443 break;
3444 }
3445 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003446 Register o_h = out.AsRegisterPairHigh<Register>();
3447 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003448
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003449 Register high = first.AsRegisterPairHigh<Register>();
3450 Register low = first.AsRegisterPairLow<Register>();
3451
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003452 if (second.IsRegister()) {
3453 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003454
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003455 Register second_reg = second.AsRegister<Register>();
3456
3457 if (op->IsShl()) {
3458 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
3459 // Shift the high part
3460 __ Lsl(o_h, high, o_l);
3461 // Shift the low part and `or` what overflew on the high part
3462 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3463 __ Lsr(temp, low, temp);
3464 __ orr(o_h, o_h, ShifterOperand(temp));
3465 // If the shift is > 32 bits, override the high part
3466 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3467 __ it(PL);
3468 __ Lsl(o_h, low, temp, PL);
3469 // Shift the low part
3470 __ Lsl(o_l, low, o_l);
3471 } else if (op->IsShr()) {
3472 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3473 // Shift the low part
3474 __ Lsr(o_l, low, o_h);
3475 // Shift the high part and `or` what underflew on the low part
3476 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3477 __ Lsl(temp, high, temp);
3478 __ orr(o_l, o_l, ShifterOperand(temp));
3479 // If the shift is > 32 bits, override the low part
3480 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3481 __ it(PL);
3482 __ Asr(o_l, high, temp, PL);
3483 // Shift the high part
3484 __ Asr(o_h, high, o_h);
3485 } else {
3486 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3487 // same as Shr except we use `Lsr`s and not `Asr`s
3488 __ Lsr(o_l, low, o_h);
3489 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3490 __ Lsl(temp, high, temp);
3491 __ orr(o_l, o_l, ShifterOperand(temp));
3492 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3493 __ it(PL);
3494 __ Lsr(o_l, high, temp, PL);
3495 __ Lsr(o_h, high, o_h);
3496 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003497 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003498 // Register allocator doesn't create partial overlap.
3499 DCHECK_NE(o_l, high);
3500 DCHECK_NE(o_h, low);
3501 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3502 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxLongShiftValue);
3503 if (shift_value > 32) {
3504 if (op->IsShl()) {
3505 __ Lsl(o_h, low, shift_value - 32);
3506 __ LoadImmediate(o_l, 0);
3507 } else if (op->IsShr()) {
3508 __ Asr(o_l, high, shift_value - 32);
3509 __ Asr(o_h, high, 31);
3510 } else {
3511 __ Lsr(o_l, high, shift_value - 32);
3512 __ LoadImmediate(o_h, 0);
3513 }
3514 } else if (shift_value == 32) {
3515 if (op->IsShl()) {
3516 __ mov(o_h, ShifterOperand(low));
3517 __ LoadImmediate(o_l, 0);
3518 } else if (op->IsShr()) {
3519 __ mov(o_l, ShifterOperand(high));
3520 __ Asr(o_h, high, 31);
3521 } else {
3522 __ mov(o_l, ShifterOperand(high));
3523 __ LoadImmediate(o_h, 0);
3524 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003525 } else if (shift_value == 1) {
3526 if (op->IsShl()) {
3527 __ Lsls(o_l, low, 1);
3528 __ adc(o_h, high, ShifterOperand(high));
3529 } else if (op->IsShr()) {
3530 __ Asrs(o_h, high, 1);
3531 __ Rrx(o_l, low);
3532 } else {
3533 __ Lsrs(o_h, high, 1);
3534 __ Rrx(o_l, low);
3535 }
3536 } else {
3537 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003538 if (op->IsShl()) {
3539 __ Lsl(o_h, high, shift_value);
3540 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3541 __ Lsl(o_l, low, shift_value);
3542 } else if (op->IsShr()) {
3543 __ Lsr(o_l, low, shift_value);
3544 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3545 __ Asr(o_h, high, shift_value);
3546 } else {
3547 __ Lsr(o_l, low, shift_value);
3548 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3549 __ Lsr(o_h, high, shift_value);
3550 }
3551 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003552 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003553 break;
3554 }
3555 default:
3556 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003557 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003558 }
3559}
3560
3561void LocationsBuilderARM::VisitShl(HShl* shl) {
3562 HandleShift(shl);
3563}
3564
3565void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3566 HandleShift(shl);
3567}
3568
3569void LocationsBuilderARM::VisitShr(HShr* shr) {
3570 HandleShift(shr);
3571}
3572
3573void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3574 HandleShift(shr);
3575}
3576
3577void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3578 HandleShift(ushr);
3579}
3580
3581void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3582 HandleShift(ushr);
3583}
3584
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003585void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003586 LocationSummary* locations =
3587 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003588 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray729645a2015-11-19 13:29:02 +00003589 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3590 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003591 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003592}
3593
3594void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003595 // Note: if heap poisoning is enabled, the entry point takes cares
3596 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003597 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003598 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003599 instruction->GetDexPc(),
3600 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003601 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003602}
3603
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003604void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3605 LocationSummary* locations =
3606 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3607 InvokeRuntimeCallingConvention calling_convention;
3608 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003609 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003610 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003611 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003612}
3613
3614void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3615 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003616 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003617 // Note: if heap poisoning is enabled, the entry point takes cares
3618 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003619 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003620 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003621 instruction->GetDexPc(),
3622 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003623 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003624}
3625
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003626void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003627 LocationSummary* locations =
3628 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003629 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3630 if (location.IsStackSlot()) {
3631 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3632 } else if (location.IsDoubleStackSlot()) {
3633 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003634 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003635 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003636}
3637
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003638void InstructionCodeGeneratorARM::VisitParameterValue(
3639 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003640 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003641}
3642
3643void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3644 LocationSummary* locations =
3645 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3646 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3647}
3648
3649void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3650 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003651}
3652
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003653void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003654 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003655 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003656 locations->SetInAt(0, Location::RequiresRegister());
3657 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003658}
3659
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003660void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3661 LocationSummary* locations = not_->GetLocations();
3662 Location out = locations->Out();
3663 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003664 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003665 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003666 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003667 break;
3668
3669 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003670 __ mvn(out.AsRegisterPairLow<Register>(),
3671 ShifterOperand(in.AsRegisterPairLow<Register>()));
3672 __ mvn(out.AsRegisterPairHigh<Register>(),
3673 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003674 break;
3675
3676 default:
3677 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3678 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003679}
3680
David Brazdil66d126e2015-04-03 16:02:44 +01003681void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3682 LocationSummary* locations =
3683 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3684 locations->SetInAt(0, Location::RequiresRegister());
3685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3686}
3687
3688void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003689 LocationSummary* locations = bool_not->GetLocations();
3690 Location out = locations->Out();
3691 Location in = locations->InAt(0);
3692 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3693}
3694
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003695void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003696 LocationSummary* locations =
3697 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003698 switch (compare->InputAt(0)->GetType()) {
3699 case Primitive::kPrimLong: {
3700 locations->SetInAt(0, Location::RequiresRegister());
3701 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003702 // Output overlaps because it is written before doing the low comparison.
3703 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003704 break;
3705 }
3706 case Primitive::kPrimFloat:
3707 case Primitive::kPrimDouble: {
3708 locations->SetInAt(0, Location::RequiresFpuRegister());
3709 locations->SetInAt(1, Location::RequiresFpuRegister());
3710 locations->SetOut(Location::RequiresRegister());
3711 break;
3712 }
3713 default:
3714 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3715 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003716}
3717
3718void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003719 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003720 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003721 Location left = locations->InAt(0);
3722 Location right = locations->InAt(1);
3723
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003724 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003725 Primitive::Type type = compare->InputAt(0)->GetType();
3726 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003727 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003728 __ cmp(left.AsRegisterPairHigh<Register>(),
3729 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003730 __ b(&less, LT);
3731 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003732 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003733 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003734 __ cmp(left.AsRegisterPairLow<Register>(),
3735 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003736 break;
3737 }
3738 case Primitive::kPrimFloat:
3739 case Primitive::kPrimDouble: {
3740 __ LoadImmediate(out, 0);
3741 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003742 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003743 } else {
3744 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3745 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3746 }
3747 __ vmstat(); // transfer FP status register to ARM APSR.
3748 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003749 break;
3750 }
3751 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003752 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003753 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003754 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003755 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003756
3757 __ Bind(&greater);
3758 __ LoadImmediate(out, 1);
3759 __ b(&done);
3760
3761 __ Bind(&less);
3762 __ LoadImmediate(out, -1);
3763
3764 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003765}
3766
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003767void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003768 LocationSummary* locations =
3769 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003770 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3771 locations->SetInAt(i, Location::Any());
3772 }
3773 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003774}
3775
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003776void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003777 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003778}
3779
Calin Juravle52c48962014-12-16 17:02:57 +00003780void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3781 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003782 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003783 switch (kind) {
3784 case MemBarrierKind::kAnyStore:
3785 case MemBarrierKind::kLoadAny:
3786 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003787 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003788 break;
3789 }
3790 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003791 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003792 break;
3793 }
3794 default:
3795 LOG(FATAL) << "Unexpected memory barrier " << kind;
3796 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003797 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003798}
3799
3800void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3801 uint32_t offset,
3802 Register out_lo,
3803 Register out_hi) {
3804 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003805 // Ensure `out_lo` is different from `addr`, so that loading
3806 // `offset` into `out_lo` does not clutter `addr`.
3807 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003808 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003809 __ add(IP, addr, ShifterOperand(out_lo));
3810 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003811 }
3812 __ ldrexd(out_lo, out_hi, addr);
3813}
3814
3815void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3816 uint32_t offset,
3817 Register value_lo,
3818 Register value_hi,
3819 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003820 Register temp2,
3821 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003822 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003823 if (offset != 0) {
3824 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003825 __ add(IP, addr, ShifterOperand(temp1));
3826 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003827 }
3828 __ Bind(&fail);
3829 // We need a load followed by store. (The address used in a STREX instruction must
3830 // be the same as the address in the most recently executed LDREX instruction.)
3831 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003832 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003833 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003834 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003835}
3836
3837void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3838 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3839
Nicolas Geoffray39468442014-09-02 15:17:15 +01003840 LocationSummary* locations =
3841 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003842 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003843
Calin Juravle52c48962014-12-16 17:02:57 +00003844 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003845 if (Primitive::IsFloatingPointType(field_type)) {
3846 locations->SetInAt(1, Location::RequiresFpuRegister());
3847 } else {
3848 locations->SetInAt(1, Location::RequiresRegister());
3849 }
3850
Calin Juravle52c48962014-12-16 17:02:57 +00003851 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003852 bool generate_volatile = field_info.IsVolatile()
3853 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003854 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003855 bool needs_write_barrier =
3856 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003857 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003858 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003859 if (needs_write_barrier) {
3860 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003861 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003862 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003863 // Arm encoding have some additional constraints for ldrexd/strexd:
3864 // - registers need to be consecutive
3865 // - the first register should be even but not R14.
3866 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3867 // enable Arm encoding.
3868 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3869
3870 locations->AddTemp(Location::RequiresRegister());
3871 locations->AddTemp(Location::RequiresRegister());
3872 if (field_type == Primitive::kPrimDouble) {
3873 // For doubles we need two more registers to copy the value.
3874 locations->AddTemp(Location::RegisterLocation(R2));
3875 locations->AddTemp(Location::RegisterLocation(R3));
3876 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003877 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003878}
3879
Calin Juravle52c48962014-12-16 17:02:57 +00003880void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003881 const FieldInfo& field_info,
3882 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003883 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3884
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003885 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003886 Register base = locations->InAt(0).AsRegister<Register>();
3887 Location value = locations->InAt(1);
3888
3889 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003890 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003891 Primitive::Type field_type = field_info.GetFieldType();
3892 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003893 bool needs_write_barrier =
3894 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003895
3896 if (is_volatile) {
3897 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3898 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003899
3900 switch (field_type) {
3901 case Primitive::kPrimBoolean:
3902 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003903 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003904 break;
3905 }
3906
3907 case Primitive::kPrimShort:
3908 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003909 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003910 break;
3911 }
3912
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003913 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003914 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003915 if (kPoisonHeapReferences && needs_write_barrier) {
3916 // Note that in the case where `value` is a null reference,
3917 // we do not enter this block, as a null reference does not
3918 // need poisoning.
3919 DCHECK_EQ(field_type, Primitive::kPrimNot);
3920 Register temp = locations->GetTemp(0).AsRegister<Register>();
3921 __ Mov(temp, value.AsRegister<Register>());
3922 __ PoisonHeapReference(temp);
3923 __ StoreToOffset(kStoreWord, temp, base, offset);
3924 } else {
3925 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3926 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003927 break;
3928 }
3929
3930 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003931 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003932 GenerateWideAtomicStore(base, offset,
3933 value.AsRegisterPairLow<Register>(),
3934 value.AsRegisterPairHigh<Register>(),
3935 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003936 locations->GetTemp(1).AsRegister<Register>(),
3937 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003938 } else {
3939 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003940 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003941 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003942 break;
3943 }
3944
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003945 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003946 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003947 break;
3948 }
3949
3950 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003951 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003952 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003953 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3954 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3955
3956 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3957
3958 GenerateWideAtomicStore(base, offset,
3959 value_reg_lo,
3960 value_reg_hi,
3961 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003962 locations->GetTemp(3).AsRegister<Register>(),
3963 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003964 } else {
3965 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003966 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003967 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003968 break;
3969 }
3970
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003971 case Primitive::kPrimVoid:
3972 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003973 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003974 }
Calin Juravle52c48962014-12-16 17:02:57 +00003975
Calin Juravle77520bc2015-01-12 18:45:46 +00003976 // Longs and doubles are handled in the switch.
3977 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3978 codegen_->MaybeRecordImplicitNullCheck(instruction);
3979 }
3980
3981 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3982 Register temp = locations->GetTemp(0).AsRegister<Register>();
3983 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003984 codegen_->MarkGCCard(
3985 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003986 }
3987
Calin Juravle52c48962014-12-16 17:02:57 +00003988 if (is_volatile) {
3989 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3990 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003991}
3992
Calin Juravle52c48962014-12-16 17:02:57 +00003993void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3994 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003995
3996 bool object_field_get_with_read_barrier =
3997 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003998 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003999 new (GetGraph()->GetArena()) LocationSummary(instruction,
4000 object_field_get_with_read_barrier ?
4001 LocationSummary::kCallOnSlowPath :
4002 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004003 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004004
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004005 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00004006 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004007 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00004008 // The output overlaps in case of volatile long: we don't want the
4009 // code generated by GenerateWideAtomicLoad to overwrite the
4010 // object's location. Likewise, in the case of an object field get
4011 // with read barriers enabled, we do not want the load to overwrite
4012 // the object's location, as we need it to emit the read barrier.
4013 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4014 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01004015
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004016 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4017 locations->SetOut(Location::RequiresFpuRegister());
4018 } else {
4019 locations->SetOut(Location::RequiresRegister(),
4020 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4021 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004022 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00004023 // Arm encoding have some additional constraints for ldrexd/strexd:
4024 // - registers need to be consecutive
4025 // - the first register should be even but not R14.
4026 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
4027 // enable Arm encoding.
4028 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4029 locations->AddTemp(Location::RequiresRegister());
4030 locations->AddTemp(Location::RequiresRegister());
4031 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004032}
4033
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004034Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4035 Opcode opcode) {
4036 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4037 if (constant->IsConstant() &&
4038 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4039 return Location::ConstantLocation(constant->AsConstant());
4040 }
4041 return Location::RequiresRegister();
4042}
4043
4044bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4045 Opcode opcode) {
4046 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4047 if (Primitive::Is64BitType(input_cst->GetType())) {
4048 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4049 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4050 } else {
4051 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4052 }
4053}
4054
4055bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4056 ShifterOperand so;
4057 ArmAssembler* assembler = codegen_->GetAssembler();
4058 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4059 return true;
4060 }
4061 Opcode neg_opcode = kNoOperand;
4062 switch (opcode) {
4063 case AND:
4064 neg_opcode = BIC;
4065 break;
4066 case ORR:
4067 neg_opcode = ORN;
4068 break;
4069 default:
4070 return false;
4071 }
4072 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4073}
4074
Calin Juravle52c48962014-12-16 17:02:57 +00004075void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4076 const FieldInfo& field_info) {
4077 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004078
Calin Juravle52c48962014-12-16 17:02:57 +00004079 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004080 Location base_loc = locations->InAt(0);
4081 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004082 Location out = locations->Out();
4083 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004084 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004085 Primitive::Type field_type = field_info.GetFieldType();
4086 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4087
4088 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004089 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00004090 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004091 break;
4092 }
4093
4094 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00004095 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004096 break;
4097 }
4098
4099 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00004100 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004101 break;
4102 }
4103
4104 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00004105 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004106 break;
4107 }
4108
4109 case Primitive::kPrimInt:
4110 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00004111 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004112 break;
4113 }
4114
4115 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00004116 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004117 GenerateWideAtomicLoad(base, offset,
4118 out.AsRegisterPairLow<Register>(),
4119 out.AsRegisterPairHigh<Register>());
4120 } else {
4121 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4122 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004123 break;
4124 }
4125
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004126 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00004127 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004128 break;
4129 }
4130
4131 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004132 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004133 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004134 Register lo = locations->GetTemp(0).AsRegister<Register>();
4135 Register hi = locations->GetTemp(1).AsRegister<Register>();
4136 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004137 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004138 __ vmovdrr(out_reg, lo, hi);
4139 } else {
4140 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004141 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004142 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004143 break;
4144 }
4145
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004146 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004147 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004148 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004149 }
Calin Juravle52c48962014-12-16 17:02:57 +00004150
Calin Juravle77520bc2015-01-12 18:45:46 +00004151 // Doubles are handled in the switch.
4152 if (field_type != Primitive::kPrimDouble) {
4153 codegen_->MaybeRecordImplicitNullCheck(instruction);
4154 }
4155
Calin Juravle52c48962014-12-16 17:02:57 +00004156 if (is_volatile) {
4157 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4158 }
Roland Levillain4d027112015-07-01 15:41:14 +01004159
4160 if (field_type == Primitive::kPrimNot) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004161 codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset);
Roland Levillain4d027112015-07-01 15:41:14 +01004162 }
Calin Juravle52c48962014-12-16 17:02:57 +00004163}
4164
4165void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4166 HandleFieldSet(instruction, instruction->GetFieldInfo());
4167}
4168
4169void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004170 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004171}
4172
4173void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4174 HandleFieldGet(instruction, instruction->GetFieldInfo());
4175}
4176
4177void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4178 HandleFieldGet(instruction, instruction->GetFieldInfo());
4179}
4180
4181void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4182 HandleFieldGet(instruction, instruction->GetFieldInfo());
4183}
4184
4185void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4186 HandleFieldGet(instruction, instruction->GetFieldInfo());
4187}
4188
4189void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4190 HandleFieldSet(instruction, instruction->GetFieldInfo());
4191}
4192
4193void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004194 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004195}
4196
Calin Juravlee460d1d2015-09-29 04:52:17 +01004197void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4198 HUnresolvedInstanceFieldGet* instruction) {
4199 FieldAccessCallingConventionARM calling_convention;
4200 codegen_->CreateUnresolvedFieldLocationSummary(
4201 instruction, instruction->GetFieldType(), calling_convention);
4202}
4203
4204void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4205 HUnresolvedInstanceFieldGet* instruction) {
4206 FieldAccessCallingConventionARM calling_convention;
4207 codegen_->GenerateUnresolvedFieldAccess(instruction,
4208 instruction->GetFieldType(),
4209 instruction->GetFieldIndex(),
4210 instruction->GetDexPc(),
4211 calling_convention);
4212}
4213
4214void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4215 HUnresolvedInstanceFieldSet* instruction) {
4216 FieldAccessCallingConventionARM calling_convention;
4217 codegen_->CreateUnresolvedFieldLocationSummary(
4218 instruction, instruction->GetFieldType(), calling_convention);
4219}
4220
4221void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4222 HUnresolvedInstanceFieldSet* instruction) {
4223 FieldAccessCallingConventionARM calling_convention;
4224 codegen_->GenerateUnresolvedFieldAccess(instruction,
4225 instruction->GetFieldType(),
4226 instruction->GetFieldIndex(),
4227 instruction->GetDexPc(),
4228 calling_convention);
4229}
4230
4231void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4232 HUnresolvedStaticFieldGet* instruction) {
4233 FieldAccessCallingConventionARM calling_convention;
4234 codegen_->CreateUnresolvedFieldLocationSummary(
4235 instruction, instruction->GetFieldType(), calling_convention);
4236}
4237
4238void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4239 HUnresolvedStaticFieldGet* instruction) {
4240 FieldAccessCallingConventionARM calling_convention;
4241 codegen_->GenerateUnresolvedFieldAccess(instruction,
4242 instruction->GetFieldType(),
4243 instruction->GetFieldIndex(),
4244 instruction->GetDexPc(),
4245 calling_convention);
4246}
4247
4248void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4249 HUnresolvedStaticFieldSet* instruction) {
4250 FieldAccessCallingConventionARM calling_convention;
4251 codegen_->CreateUnresolvedFieldLocationSummary(
4252 instruction, instruction->GetFieldType(), calling_convention);
4253}
4254
4255void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4256 HUnresolvedStaticFieldSet* instruction) {
4257 FieldAccessCallingConventionARM calling_convention;
4258 codegen_->GenerateUnresolvedFieldAccess(instruction,
4259 instruction->GetFieldType(),
4260 instruction->GetFieldIndex(),
4261 instruction->GetDexPc(),
4262 calling_convention);
4263}
4264
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004265void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004266 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4267 ? LocationSummary::kCallOnSlowPath
4268 : LocationSummary::kNoCall;
4269 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004270 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004271 if (instruction->HasUses()) {
4272 locations->SetOut(Location::SameAsFirstInput());
4273 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004274}
4275
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004276void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004277 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4278 return;
4279 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004280 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004281
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004282 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
4283 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4284}
4285
4286void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004287 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004288 codegen_->AddSlowPath(slow_path);
4289
4290 LocationSummary* locations = instruction->GetLocations();
4291 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004292
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004293 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004294}
4295
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004296void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004297 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004298 GenerateImplicitNullCheck(instruction);
4299 } else {
4300 GenerateExplicitNullCheck(instruction);
4301 }
4302}
4303
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004304void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004305 bool object_array_get_with_read_barrier =
4306 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004307 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004308 new (GetGraph()->GetArena()) LocationSummary(instruction,
4309 object_array_get_with_read_barrier ?
4310 LocationSummary::kCallOnSlowPath :
4311 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004312 locations->SetInAt(0, Location::RequiresRegister());
4313 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004314 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4315 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4316 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004317 // The output overlaps in the case of an object array get with
4318 // read barriers enabled: we do not want the move to overwrite the
4319 // array's location, as we need it to emit the read barrier.
4320 locations->SetOut(
4321 Location::RequiresRegister(),
4322 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004323 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004324}
4325
4326void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4327 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004328 Location obj_loc = locations->InAt(0);
4329 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004330 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01004331 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004332
Roland Levillain4d027112015-07-01 15:41:14 +01004333 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004334 case Primitive::kPrimBoolean: {
4335 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004336 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004337 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004338 size_t offset =
4339 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004340 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4341 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004342 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004343 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4344 }
4345 break;
4346 }
4347
4348 case Primitive::kPrimByte: {
4349 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004350 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004351 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004352 size_t offset =
4353 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004354 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4355 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004356 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004357 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4358 }
4359 break;
4360 }
4361
4362 case Primitive::kPrimShort: {
4363 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004364 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004365 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004366 size_t offset =
4367 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004368 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4369 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004370 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004371 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4372 }
4373 break;
4374 }
4375
4376 case Primitive::kPrimChar: {
4377 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004378 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004379 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004380 size_t offset =
4381 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004382 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4383 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004384 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004385 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4386 }
4387 break;
4388 }
4389
4390 case Primitive::kPrimInt:
4391 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00004392 static_assert(
4393 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4394 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004395 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004396 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004397 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004398 size_t offset =
4399 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004400 __ LoadFromOffset(kLoadWord, out, obj, offset);
4401 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004402 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004403 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4404 }
4405 break;
4406 }
4407
4408 case Primitive::kPrimLong: {
4409 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004410 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004411 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004412 size_t offset =
4413 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004414 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004415 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004416 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004417 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004418 }
4419 break;
4420 }
4421
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004422 case Primitive::kPrimFloat: {
4423 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4424 Location out = locations->Out();
4425 DCHECK(out.IsFpuRegister());
4426 if (index.IsConstant()) {
4427 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4428 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4429 } else {
4430 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4431 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4432 }
4433 break;
4434 }
4435
4436 case Primitive::kPrimDouble: {
4437 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4438 Location out = locations->Out();
4439 DCHECK(out.IsFpuRegisterPair());
4440 if (index.IsConstant()) {
4441 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4442 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4443 } else {
4444 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4445 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4446 }
4447 break;
4448 }
4449
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004450 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004451 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004452 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004453 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004454 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004455
4456 if (type == Primitive::kPrimNot) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004457 static_assert(
4458 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4459 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4460 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4461 Location out = locations->Out();
4462 if (index.IsConstant()) {
4463 uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4464 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset);
4465 } else {
4466 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index);
4467 }
Roland Levillain4d027112015-07-01 15:41:14 +01004468 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004469}
4470
4471void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004472 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004473
4474 bool needs_write_barrier =
4475 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004476 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4477 bool object_array_set_with_read_barrier =
4478 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004479
Nicolas Geoffray39468442014-09-02 15:17:15 +01004480 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004481 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004482 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4483 LocationSummary::kCallOnSlowPath :
4484 LocationSummary::kNoCall);
4485
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004486 locations->SetInAt(0, Location::RequiresRegister());
4487 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4488 if (Primitive::IsFloatingPointType(value_type)) {
4489 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004490 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004491 locations->SetInAt(2, Location::RequiresRegister());
4492 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004493 if (needs_write_barrier) {
4494 // Temporary registers for the write barrier.
4495 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004496 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004497 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004498}
4499
4500void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4501 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004502 Location array_loc = locations->InAt(0);
4503 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004504 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004505 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004506 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004507 bool needs_write_barrier =
4508 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004509
4510 switch (value_type) {
4511 case Primitive::kPrimBoolean:
4512 case Primitive::kPrimByte: {
4513 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004514 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004515 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004516 size_t offset =
4517 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004518 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004519 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004520 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004521 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4522 }
4523 break;
4524 }
4525
4526 case Primitive::kPrimShort:
4527 case Primitive::kPrimChar: {
4528 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004529 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004530 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004531 size_t offset =
4532 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004533 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004534 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004535 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004536 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4537 }
4538 break;
4539 }
4540
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004541 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004542 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004543 Location value_loc = locations->InAt(2);
4544 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004545 Register source = value;
4546
4547 if (instruction->InputAt(2)->IsNullConstant()) {
4548 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004549 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004550 size_t offset =
4551 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004552 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004553 } else {
4554 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004555 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004556 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004557 }
Roland Levillain3b359c72015-11-17 19:35:12 +00004558 DCHECK(!needs_write_barrier);
4559 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004560 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004561 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004562
4563 DCHECK(needs_write_barrier);
4564 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4565 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4566 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4567 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4568 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4569 Label done;
4570 SlowPathCode* slow_path = nullptr;
4571
Roland Levillain3b359c72015-11-17 19:35:12 +00004572 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004573 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4574 codegen_->AddSlowPath(slow_path);
4575 if (instruction->GetValueCanBeNull()) {
4576 Label non_zero;
4577 __ CompareAndBranchIfNonZero(value, &non_zero);
4578 if (index.IsConstant()) {
4579 size_t offset =
4580 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4581 __ StoreToOffset(kStoreWord, value, array, offset);
4582 } else {
4583 DCHECK(index.IsRegister()) << index;
4584 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4585 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4586 }
4587 codegen_->MaybeRecordImplicitNullCheck(instruction);
4588 __ b(&done);
4589 __ Bind(&non_zero);
4590 }
4591
Roland Levillain3b359c72015-11-17 19:35:12 +00004592 if (kEmitCompilerReadBarrier) {
4593 // When read barriers are enabled, the type checking
4594 // instrumentation requires two read barriers:
4595 //
4596 // __ Mov(temp2, temp1);
4597 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4598 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4599 // codegen_->GenerateReadBarrier(
4600 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4601 //
4602 // // /* HeapReference<Class> */ temp2 = value->klass_
4603 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4604 // codegen_->GenerateReadBarrier(
4605 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4606 //
4607 // __ cmp(temp1, ShifterOperand(temp2));
4608 //
4609 // However, the second read barrier may trash `temp`, as it
4610 // is a temporary register, and as such would not be saved
4611 // along with live registers before calling the runtime (nor
4612 // restored afterwards). So in this case, we bail out and
4613 // delegate the work to the array set slow path.
4614 //
4615 // TODO: Extend the register allocator to support a new
4616 // "(locally) live temp" location so as to avoid always
4617 // going into the slow path when read barriers are enabled.
4618 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004619 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004620 // /* HeapReference<Class> */ temp1 = array->klass_
4621 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4622 codegen_->MaybeRecordImplicitNullCheck(instruction);
4623 __ MaybeUnpoisonHeapReference(temp1);
4624
4625 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4626 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4627 // /* HeapReference<Class> */ temp2 = value->klass_
4628 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4629 // If heap poisoning is enabled, no need to unpoison `temp1`
4630 // nor `temp2`, as we are comparing two poisoned references.
4631 __ cmp(temp1, ShifterOperand(temp2));
4632
4633 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4634 Label do_put;
4635 __ b(&do_put, EQ);
4636 // If heap poisoning is enabled, the `temp1` reference has
4637 // not been unpoisoned yet; unpoison it now.
4638 __ MaybeUnpoisonHeapReference(temp1);
4639
4640 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4641 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4642 // If heap poisoning is enabled, no need to unpoison
4643 // `temp1`, as we are comparing against null below.
4644 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4645 __ Bind(&do_put);
4646 } else {
4647 __ b(slow_path->GetEntryLabel(), NE);
4648 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004649 }
4650 }
4651
4652 if (kPoisonHeapReferences) {
4653 // Note that in the case where `value` is a null reference,
4654 // we do not enter this block, as a null reference does not
4655 // need poisoning.
4656 DCHECK_EQ(value_type, Primitive::kPrimNot);
4657 __ Mov(temp1, value);
4658 __ PoisonHeapReference(temp1);
4659 source = temp1;
4660 }
4661
4662 if (index.IsConstant()) {
4663 size_t offset =
4664 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4665 __ StoreToOffset(kStoreWord, source, array, offset);
4666 } else {
4667 DCHECK(index.IsRegister()) << index;
4668 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4669 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4670 }
4671
Roland Levillain3b359c72015-11-17 19:35:12 +00004672 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004673 codegen_->MaybeRecordImplicitNullCheck(instruction);
4674 }
4675
4676 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4677
4678 if (done.IsLinked()) {
4679 __ Bind(&done);
4680 }
4681
4682 if (slow_path != nullptr) {
4683 __ Bind(slow_path->GetExitLabel());
4684 }
4685
4686 break;
4687 }
4688
4689 case Primitive::kPrimInt: {
4690 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4691 Register value = locations->InAt(2).AsRegister<Register>();
4692 if (index.IsConstant()) {
4693 size_t offset =
4694 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4695 __ StoreToOffset(kStoreWord, value, array, offset);
4696 } else {
4697 DCHECK(index.IsRegister()) << index;
4698 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4699 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4700 }
4701
4702 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004703 break;
4704 }
4705
4706 case Primitive::kPrimLong: {
4707 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004708 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004709 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004710 size_t offset =
4711 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004712 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004713 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004714 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004715 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004716 }
4717 break;
4718 }
4719
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004720 case Primitive::kPrimFloat: {
4721 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4722 Location value = locations->InAt(2);
4723 DCHECK(value.IsFpuRegister());
4724 if (index.IsConstant()) {
4725 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004726 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004727 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004728 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004729 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4730 }
4731 break;
4732 }
4733
4734 case Primitive::kPrimDouble: {
4735 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4736 Location value = locations->InAt(2);
4737 DCHECK(value.IsFpuRegisterPair());
4738 if (index.IsConstant()) {
4739 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004740 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004741 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004742 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004743 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4744 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004745
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004746 break;
4747 }
4748
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004749 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004750 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004751 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004752 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004753
4754 // Ints and objects are handled in the switch.
4755 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4756 codegen_->MaybeRecordImplicitNullCheck(instruction);
4757 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004758}
4759
4760void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004761 LocationSummary* locations =
4762 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004763 locations->SetInAt(0, Location::RequiresRegister());
4764 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004765}
4766
4767void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4768 LocationSummary* locations = instruction->GetLocations();
4769 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004770 Register obj = locations->InAt(0).AsRegister<Register>();
4771 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004772 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004773 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004774}
4775
4776void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004777 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4778 ? LocationSummary::kCallOnSlowPath
4779 : LocationSummary::kNoCall;
4780 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004781 locations->SetInAt(0, Location::RequiresRegister());
4782 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004783 if (instruction->HasUses()) {
4784 locations->SetOut(Location::SameAsFirstInput());
4785 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004786}
4787
4788void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4789 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004790 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004791 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004792 codegen_->AddSlowPath(slow_path);
4793
Roland Levillain271ab9c2014-11-27 15:23:57 +00004794 Register index = locations->InAt(0).AsRegister<Register>();
4795 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004796
4797 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004798 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004799}
4800
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004801void CodeGeneratorARM::MarkGCCard(Register temp,
4802 Register card,
4803 Register object,
4804 Register value,
4805 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004806 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004807 if (can_be_null) {
4808 __ CompareAndBranchIfZero(value, &is_null);
4809 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004810 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4811 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4812 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004813 if (can_be_null) {
4814 __ Bind(&is_null);
4815 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004816}
4817
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004818void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4819 temp->SetLocations(nullptr);
4820}
4821
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004822void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004823 // Nothing to do, this is driven by the code generator.
4824}
4825
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004826void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004827 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004828}
4829
4830void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004831 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4832}
4833
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004834void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4835 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4836}
4837
4838void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004839 HBasicBlock* block = instruction->GetBlock();
4840 if (block->GetLoopInformation() != nullptr) {
4841 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4842 // The back edge will generate the suspend check.
4843 return;
4844 }
4845 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4846 // The goto will generate the suspend check.
4847 return;
4848 }
4849 GenerateSuspendCheck(instruction, nullptr);
4850}
4851
4852void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4853 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004854 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004855 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4856 if (slow_path == nullptr) {
4857 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4858 instruction->SetSlowPath(slow_path);
4859 codegen_->AddSlowPath(slow_path);
4860 if (successor != nullptr) {
4861 DCHECK(successor->IsLoopHeader());
4862 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4863 }
4864 } else {
4865 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4866 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004867
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004868 __ LoadFromOffset(
4869 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004870 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004871 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004872 __ Bind(slow_path->GetReturnLabel());
4873 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004874 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004875 __ b(slow_path->GetEntryLabel());
4876 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004877}
4878
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004879ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4880 return codegen_->GetAssembler();
4881}
4882
4883void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004884 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004885 Location source = move->GetSource();
4886 Location destination = move->GetDestination();
4887
4888 if (source.IsRegister()) {
4889 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004890 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004891 } else {
4892 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004893 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004894 SP, destination.GetStackIndex());
4895 }
4896 } else if (source.IsStackSlot()) {
4897 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004898 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004899 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004900 } else if (destination.IsFpuRegister()) {
4901 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004902 } else {
4903 DCHECK(destination.IsStackSlot());
4904 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4905 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4906 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004907 } else if (source.IsFpuRegister()) {
4908 if (destination.IsFpuRegister()) {
4909 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004910 } else {
4911 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004912 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4913 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004914 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004915 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004916 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4917 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004918 } else if (destination.IsRegisterPair()) {
4919 DCHECK(ExpectedPairLayout(destination));
4920 __ LoadFromOffset(
4921 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4922 } else {
4923 DCHECK(destination.IsFpuRegisterPair()) << destination;
4924 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4925 SP,
4926 source.GetStackIndex());
4927 }
4928 } else if (source.IsRegisterPair()) {
4929 if (destination.IsRegisterPair()) {
4930 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4931 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4932 } else {
4933 DCHECK(destination.IsDoubleStackSlot()) << destination;
4934 DCHECK(ExpectedPairLayout(source));
4935 __ StoreToOffset(
4936 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4937 }
4938 } else if (source.IsFpuRegisterPair()) {
4939 if (destination.IsFpuRegisterPair()) {
4940 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4941 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4942 } else {
4943 DCHECK(destination.IsDoubleStackSlot()) << destination;
4944 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4945 SP,
4946 destination.GetStackIndex());
4947 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004948 } else {
4949 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004950 HConstant* constant = source.GetConstant();
4951 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4952 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004953 if (destination.IsRegister()) {
4954 __ LoadImmediate(destination.AsRegister<Register>(), value);
4955 } else {
4956 DCHECK(destination.IsStackSlot());
4957 __ LoadImmediate(IP, value);
4958 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4959 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004960 } else if (constant->IsLongConstant()) {
4961 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004962 if (destination.IsRegisterPair()) {
4963 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4964 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004965 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004966 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004967 __ LoadImmediate(IP, Low32Bits(value));
4968 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4969 __ LoadImmediate(IP, High32Bits(value));
4970 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4971 }
4972 } else if (constant->IsDoubleConstant()) {
4973 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004974 if (destination.IsFpuRegisterPair()) {
4975 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004976 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004977 DCHECK(destination.IsDoubleStackSlot()) << destination;
4978 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004979 __ LoadImmediate(IP, Low32Bits(int_value));
4980 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4981 __ LoadImmediate(IP, High32Bits(int_value));
4982 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4983 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004984 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004985 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004986 float value = constant->AsFloatConstant()->GetValue();
4987 if (destination.IsFpuRegister()) {
4988 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4989 } else {
4990 DCHECK(destination.IsStackSlot());
4991 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4992 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4993 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004994 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004995 }
4996}
4997
4998void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4999 __ Mov(IP, reg);
5000 __ LoadFromOffset(kLoadWord, reg, SP, mem);
5001 __ StoreToOffset(kStoreWord, IP, SP, mem);
5002}
5003
5004void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5005 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5006 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5007 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5008 SP, mem1 + stack_offset);
5009 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5010 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5011 SP, mem2 + stack_offset);
5012 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5013}
5014
5015void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005016 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005017 Location source = move->GetSource();
5018 Location destination = move->GetDestination();
5019
5020 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005021 DCHECK_NE(source.AsRegister<Register>(), IP);
5022 DCHECK_NE(destination.AsRegister<Register>(), IP);
5023 __ Mov(IP, source.AsRegister<Register>());
5024 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5025 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005026 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005027 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005028 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005029 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005030 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5031 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005032 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005033 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005034 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005035 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005036 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005037 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005038 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005039 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005040 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5041 destination.AsRegisterPairHigh<Register>(),
5042 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005043 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005044 Register low_reg = source.IsRegisterPair()
5045 ? source.AsRegisterPairLow<Register>()
5046 : destination.AsRegisterPairLow<Register>();
5047 int mem = source.IsRegisterPair()
5048 ? destination.GetStackIndex()
5049 : source.GetStackIndex();
5050 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005051 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005052 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005053 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005054 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005055 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5056 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005057 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005058 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005059 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005060 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5061 DRegister reg = source.IsFpuRegisterPair()
5062 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5063 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5064 int mem = source.IsFpuRegisterPair()
5065 ? destination.GetStackIndex()
5066 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005067 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005068 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005069 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005070 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5071 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5072 : destination.AsFpuRegister<SRegister>();
5073 int mem = source.IsFpuRegister()
5074 ? destination.GetStackIndex()
5075 : source.GetStackIndex();
5076
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005077 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005078 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005079 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005080 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005081 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5082 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005083 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005084 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005085 }
5086}
5087
5088void ParallelMoveResolverARM::SpillScratch(int reg) {
5089 __ Push(static_cast<Register>(reg));
5090}
5091
5092void ParallelMoveResolverARM::RestoreScratch(int reg) {
5093 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005094}
5095
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005096void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005097 InvokeRuntimeCallingConvention calling_convention;
5098 CodeGenerator::CreateLoadClassLocationSummary(
5099 cls,
5100 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain3b359c72015-11-17 19:35:12 +00005101 Location::RegisterLocation(R0),
5102 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005103}
5104
5105void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005106 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005107 if (cls->NeedsAccessCheck()) {
5108 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5109 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5110 cls,
5111 cls->GetDexPc(),
5112 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005113 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005114 return;
5115 }
5116
Roland Levillain3b359c72015-11-17 19:35:12 +00005117 Location out_loc = locations->Out();
5118 Register out = out_loc.AsRegister<Register>();
Calin Juravle580b6092015-10-06 17:35:58 +01005119 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005120
Calin Juravle580b6092015-10-06 17:35:58 +01005121 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005122 DCHECK(!cls->CanCallRuntime());
5123 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillain3b359c72015-11-17 19:35:12 +00005124 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5125 if (kEmitCompilerReadBarrier) {
5126 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5127 __ AddConstant(out, current_method, declaring_class_offset);
5128 // /* mirror::Class* */ out = out->Read()
5129 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5130 } else {
5131 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5132 __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5133 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005134 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00005135 // /* GcRoot<mirror::Class>[] */ out =
5136 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005137 __ LoadFromOffset(kLoadWord,
5138 out,
5139 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01005140 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Roland Levillain3b359c72015-11-17 19:35:12 +00005141
5142 size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5143 if (kEmitCompilerReadBarrier) {
5144 // /* GcRoot<mirror::Class>* */ out = &out[type_index]
5145 __ AddConstant(out, out, cache_offset);
5146 // /* mirror::Class* */ out = out->Read()
5147 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc);
5148 } else {
5149 // /* GcRoot<mirror::Class> */ out = out[type_index]
5150 __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5151 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005152
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005153 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5154 DCHECK(cls->CanCallRuntime());
5155 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5156 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5157 codegen_->AddSlowPath(slow_path);
5158 if (!cls->IsInDexCache()) {
5159 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5160 }
5161 if (cls->MustGenerateClinitCheck()) {
5162 GenerateClassInitializationCheck(slow_path, out);
5163 } else {
5164 __ Bind(slow_path->GetExitLabel());
5165 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005166 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005167 }
5168}
5169
5170void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5171 LocationSummary* locations =
5172 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5173 locations->SetInAt(0, Location::RequiresRegister());
5174 if (check->HasUses()) {
5175 locations->SetOut(Location::SameAsFirstInput());
5176 }
5177}
5178
5179void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005180 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005181 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005182 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005183 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005184 GenerateClassInitializationCheck(slow_path,
5185 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005186}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005187
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005188void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005189 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005190 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5191 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5192 __ b(slow_path->GetEntryLabel(), LT);
5193 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5194 // properly. Therefore, we do a memory fence.
5195 __ dmb(ISH);
5196 __ Bind(slow_path->GetExitLabel());
5197}
5198
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005199void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005200 LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
5201 ? LocationSummary::kCallOnSlowPath
5202 : LocationSummary::kNoCall;
5203 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005204 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005205 locations->SetOut(Location::RequiresRegister());
5206}
5207
5208void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005209 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005210 Location out_loc = locations->Out();
5211 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005212 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005213
5214 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value();
5215 if (kEmitCompilerReadBarrier) {
5216 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_)
5217 __ AddConstant(out, current_method, declaring_class_offset);
5218 // /* mirror::Class* */ out = out->Read()
5219 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5220 } else {
5221 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5222 __ LoadFromOffset(kLoadWord, out, current_method, declaring_class_offset);
5223 }
5224
5225 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
Mathieu Chartiereace4582014-11-24 18:29:54 -08005226 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Roland Levillain3b359c72015-11-17 19:35:12 +00005227
5228 size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex());
5229 if (kEmitCompilerReadBarrier) {
5230 // /* GcRoot<mirror::String>* */ out = &out[string_index]
5231 __ AddConstant(out, out, cache_offset);
5232 // /* mirror::String* */ out = out->Read()
5233 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc);
5234 } else {
5235 // /* GcRoot<mirror::String> */ out = out[string_index]
5236 __ LoadFromOffset(kLoadWord, out, out, cache_offset);
5237 }
5238
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005239 if (!load->IsInDexCache()) {
5240 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5241 codegen_->AddSlowPath(slow_path);
5242 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5243 __ Bind(slow_path->GetExitLabel());
5244 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005245}
5246
David Brazdilcb1c0552015-08-04 16:22:25 +01005247static int32_t GetExceptionTlsOffset() {
5248 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5249}
5250
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005251void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5252 LocationSummary* locations =
5253 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5254 locations->SetOut(Location::RequiresRegister());
5255}
5256
5257void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005258 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005259 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5260}
5261
5262void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5263 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5264}
5265
5266void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005267 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005268 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005269}
5270
5271void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5272 LocationSummary* locations =
5273 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5274 InvokeRuntimeCallingConvention calling_convention;
5275 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5276}
5277
5278void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5279 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005280 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005281 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005282}
5283
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005284void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005285 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005286 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5287 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005288 case TypeCheckKind::kExactCheck:
5289 case TypeCheckKind::kAbstractClassCheck:
5290 case TypeCheckKind::kClassHierarchyCheck:
5291 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005292 call_kind =
5293 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005294 break;
5295 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005296 case TypeCheckKind::kUnresolvedCheck:
5297 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005298 call_kind = LocationSummary::kCallOnSlowPath;
5299 break;
5300 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005301
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005302 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005303 locations->SetInAt(0, Location::RequiresRegister());
5304 locations->SetInAt(1, Location::RequiresRegister());
5305 // The "out" register is used as a temporary, so it overlaps with the inputs.
5306 // Note that TypeCheckSlowPathARM uses this register too.
5307 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5308 // When read barriers are enabled, we need a temporary register for
5309 // some cases.
5310 if (kEmitCompilerReadBarrier &&
5311 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5312 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5313 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
5314 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005315 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005316}
5317
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005318void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005319 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005320 Location obj_loc = locations->InAt(0);
5321 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005322 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005323 Location out_loc = locations->Out();
5324 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005325 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005326 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5327 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5328 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005329 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005330 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005331
5332 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005333 // avoid null check if we know obj is not null.
5334 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005335 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005336 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005337
Roland Levillain3b359c72015-11-17 19:35:12 +00005338 // /* HeapReference<Class> */ out = obj->klass_
5339 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
5340 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005341
5342 switch (instruction->GetTypeCheckKind()) {
5343 case TypeCheckKind::kExactCheck: {
5344 __ cmp(out, ShifterOperand(cls));
5345 // Classes must be equal for the instanceof to succeed.
5346 __ b(&zero, NE);
5347 __ LoadImmediate(out, 1);
5348 __ b(&done);
5349 break;
5350 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005351
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005352 case TypeCheckKind::kAbstractClassCheck: {
5353 // If the class is abstract, we eagerly fetch the super class of the
5354 // object to avoid doing a comparison we know will fail.
5355 Label loop;
5356 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005357 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5358 if (kEmitCompilerReadBarrier) {
5359 // Save the value of `out` into `temp` before overwriting it
5360 // in the following move operation, as we will need it for the
5361 // read barrier below.
5362 Register temp = temp_loc.AsRegister<Register>();
5363 __ Mov(temp, out);
5364 }
5365 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005366 __ LoadFromOffset(kLoadWord, out, out, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005367 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005368 // If `out` is null, we use it for the result, and jump to `done`.
5369 __ CompareAndBranchIfZero(out, &done);
5370 __ cmp(out, ShifterOperand(cls));
5371 __ b(&loop, NE);
5372 __ LoadImmediate(out, 1);
5373 if (zero.IsLinked()) {
5374 __ b(&done);
5375 }
5376 break;
5377 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005378
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005379 case TypeCheckKind::kClassHierarchyCheck: {
5380 // Walk over the class hierarchy to find a match.
5381 Label loop, success;
5382 __ Bind(&loop);
5383 __ cmp(out, ShifterOperand(cls));
5384 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005385 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5386 if (kEmitCompilerReadBarrier) {
5387 // Save the value of `out` into `temp` before overwriting it
5388 // in the following move operation, as we will need it for the
5389 // read barrier below.
5390 Register temp = temp_loc.AsRegister<Register>();
5391 __ Mov(temp, out);
5392 }
5393 // /* HeapReference<Class> */ out = out->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005394 __ LoadFromOffset(kLoadWord, out, out, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005395 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005396 __ CompareAndBranchIfNonZero(out, &loop);
5397 // If `out` is null, we use it for the result, and jump to `done`.
5398 __ b(&done);
5399 __ Bind(&success);
5400 __ LoadImmediate(out, 1);
5401 if (zero.IsLinked()) {
5402 __ b(&done);
5403 }
5404 break;
5405 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005406
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005407 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005408 // Do an exact check.
5409 Label exact_check;
5410 __ cmp(out, ShifterOperand(cls));
5411 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005412 // Otherwise, we need to check that the object's class is a non-primitive array.
5413 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation();
5414 if (kEmitCompilerReadBarrier) {
5415 // Save the value of `out` into `temp` before overwriting it
5416 // in the following move operation, as we will need it for the
5417 // read barrier below.
5418 Register temp = temp_loc.AsRegister<Register>();
5419 __ Mov(temp, out);
5420 }
5421 // /* HeapReference<Class> */ out = out->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005422 __ LoadFromOffset(kLoadWord, out, out, component_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005423 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005424 // If `out` is null, we use it for the result, and jump to `done`.
5425 __ CompareAndBranchIfZero(out, &done);
5426 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5427 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5428 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005429 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005430 __ LoadImmediate(out, 1);
5431 __ b(&done);
5432 break;
5433 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005434
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005435 case TypeCheckKind::kArrayCheck: {
5436 __ cmp(out, ShifterOperand(cls));
5437 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005438 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5439 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005440 codegen_->AddSlowPath(slow_path);
5441 __ b(slow_path->GetEntryLabel(), NE);
5442 __ LoadImmediate(out, 1);
5443 if (zero.IsLinked()) {
5444 __ b(&done);
5445 }
5446 break;
5447 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005448
Calin Juravle98893e12015-10-02 21:05:03 +01005449 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005450 case TypeCheckKind::kInterfaceCheck: {
5451 // Note that we indeed only call on slow path, but we always go
5452 // into the slow path for the unresolved & interface check
5453 // cases.
5454 //
5455 // We cannot directly call the InstanceofNonTrivial runtime
5456 // entry point without resorting to a type checking slow path
5457 // here (i.e. by calling InvokeRuntime directly), as it would
5458 // require to assign fixed registers for the inputs of this
5459 // HInstanceOf instruction (following the runtime calling
5460 // convention), which might be cluttered by the potential first
5461 // read barrier emission at the beginning of this method.
5462 DCHECK(locations->OnlyCallsOnSlowPath());
5463 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5464 /* is_fatal */ false);
5465 codegen_->AddSlowPath(slow_path);
5466 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005467 if (zero.IsLinked()) {
5468 __ b(&done);
5469 }
5470 break;
5471 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005472 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005473
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005474 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005475 __ Bind(&zero);
5476 __ LoadImmediate(out, 0);
5477 }
5478
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005479 if (done.IsLinked()) {
5480 __ Bind(&done);
5481 }
5482
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005483 if (slow_path != nullptr) {
5484 __ Bind(slow_path->GetExitLabel());
5485 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005486}
5487
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005488void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005489 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5490 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5491
Roland Levillain3b359c72015-11-17 19:35:12 +00005492 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5493 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005494 case TypeCheckKind::kExactCheck:
5495 case TypeCheckKind::kAbstractClassCheck:
5496 case TypeCheckKind::kClassHierarchyCheck:
5497 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005498 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5499 LocationSummary::kCallOnSlowPath :
5500 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005501 break;
5502 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005503 case TypeCheckKind::kUnresolvedCheck:
5504 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005505 call_kind = LocationSummary::kCallOnSlowPath;
5506 break;
5507 }
5508
Roland Levillain3b359c72015-11-17 19:35:12 +00005509 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5510 locations->SetInAt(0, Location::RequiresRegister());
5511 locations->SetInAt(1, Location::RequiresRegister());
5512 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5513 locations->AddTemp(Location::RequiresRegister());
5514 // When read barriers are enabled, we need an additional temporary
5515 // register for some cases.
5516 if (kEmitCompilerReadBarrier &&
5517 (type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5518 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5519 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005520 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005521 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005522}
5523
5524void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
5525 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005526 Location obj_loc = locations->InAt(0);
5527 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005528 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005529 Location temp_loc = locations->GetTemp(0);
5530 Register temp = temp_loc.AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005531 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005532 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5533 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5534 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005535
Roland Levillain3b359c72015-11-17 19:35:12 +00005536 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5537 bool is_type_check_slow_path_fatal =
5538 (type_check_kind == TypeCheckKind::kExactCheck ||
5539 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5540 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5541 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5542 !instruction->CanThrowIntoCatchBlock();
5543 SlowPathCode* type_check_slow_path =
5544 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5545 is_type_check_slow_path_fatal);
5546 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005547
5548 Label done;
5549 // Avoid null check if we know obj is not null.
5550 if (instruction->MustDoNullCheck()) {
5551 __ CompareAndBranchIfZero(obj, &done);
5552 }
5553
Roland Levillain3b359c72015-11-17 19:35:12 +00005554 // /* HeapReference<Class> */ temp = obj->klass_
5555 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5556 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005557
Roland Levillain3b359c72015-11-17 19:35:12 +00005558 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005559 case TypeCheckKind::kExactCheck:
5560 case TypeCheckKind::kArrayCheck: {
5561 __ cmp(temp, ShifterOperand(cls));
5562 // Jump to slow path for throwing the exception or doing a
5563 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005564 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005565 break;
5566 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005567
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005568 case TypeCheckKind::kAbstractClassCheck: {
5569 // If the class is abstract, we eagerly fetch the super class of the
5570 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005571 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005572 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005573 Location temp2_loc =
5574 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5575 if (kEmitCompilerReadBarrier) {
5576 // Save the value of `temp` into `temp2` before overwriting it
5577 // in the following move operation, as we will need it for the
5578 // read barrier below.
5579 Register temp2 = temp2_loc.AsRegister<Register>();
5580 __ Mov(temp2, temp);
5581 }
5582 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005583 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005584 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5585
5586 // If the class reference currently in `temp` is not null, jump
5587 // to the `compare_classes` label to compare it with the checked
5588 // class.
5589 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5590 // Otherwise, jump to the slow path to throw the exception.
5591 //
5592 // But before, move back the object's class into `temp` before
5593 // going into the slow path, as it has been overwritten in the
5594 // meantime.
5595 // /* HeapReference<Class> */ temp = obj->klass_
5596 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5597 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5598 __ b(type_check_slow_path->GetEntryLabel());
5599
5600 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005601 __ cmp(temp, ShifterOperand(cls));
5602 __ b(&loop, NE);
5603 break;
5604 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005605
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005606 case TypeCheckKind::kClassHierarchyCheck: {
5607 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005608 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005609 __ Bind(&loop);
5610 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005611 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005612
5613 Location temp2_loc =
5614 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5615 if (kEmitCompilerReadBarrier) {
5616 // Save the value of `temp` into `temp2` before overwriting it
5617 // in the following move operation, as we will need it for the
5618 // read barrier below.
5619 Register temp2 = temp2_loc.AsRegister<Register>();
5620 __ Mov(temp2, temp);
5621 }
5622 // /* HeapReference<Class> */ temp = temp->super_class_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005623 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005624 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset);
5625
5626 // If the class reference currently in `temp` is not null, jump
5627 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005628 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005629 // Otherwise, jump to the slow path to throw the exception.
5630 //
5631 // But before, move back the object's class into `temp` before
5632 // going into the slow path, as it has been overwritten in the
5633 // meantime.
5634 // /* HeapReference<Class> */ temp = obj->klass_
5635 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5636 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5637 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005638 break;
5639 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005640
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005641 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005642 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005643 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005644 __ cmp(temp, ShifterOperand(cls));
5645 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005646
5647 // Otherwise, we need to check that the object's class is a non-primitive array.
5648 Location temp2_loc =
5649 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation();
5650 if (kEmitCompilerReadBarrier) {
5651 // Save the value of `temp` into `temp2` before overwriting it
5652 // in the following move operation, as we will need it for the
5653 // read barrier below.
5654 Register temp2 = temp2_loc.AsRegister<Register>();
5655 __ Mov(temp2, temp);
5656 }
5657 // /* HeapReference<Class> */ temp = temp->component_type_
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005658 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005659 codegen_->MaybeGenerateReadBarrier(
5660 instruction, temp_loc, temp_loc, temp2_loc, component_offset);
5661
5662 // If the component type is not null (i.e. the object is indeed
5663 // an array), jump to label `check_non_primitive_component_type`
5664 // to further check that this component type is not a primitive
5665 // type.
5666 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5667 // Otherwise, jump to the slow path to throw the exception.
5668 //
5669 // But before, move back the object's class into `temp` before
5670 // going into the slow path, as it has been overwritten in the
5671 // meantime.
5672 // /* HeapReference<Class> */ temp = obj->klass_
5673 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5674 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5675 __ b(type_check_slow_path->GetEntryLabel());
5676
5677 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005678 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005679 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5680 __ CompareAndBranchIfZero(temp, &done);
5681 // Same comment as above regarding `temp` and the slow path.
5682 // /* HeapReference<Class> */ temp = obj->klass_
5683 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
5684 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset);
5685 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005686 break;
5687 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005688
Calin Juravle98893e12015-10-02 21:05:03 +01005689 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005690 case TypeCheckKind::kInterfaceCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005691 // We always go into the type check slow path for the unresolved &
5692 // interface check cases.
5693 //
5694 // We cannot directly call the CheckCast runtime entry point
5695 // without resorting to a type checking slow path here (i.e. by
5696 // calling InvokeRuntime directly), as it would require to
5697 // assign fixed registers for the inputs of this HInstanceOf
5698 // instruction (following the runtime calling convention), which
5699 // might be cluttered by the potential first read barrier
5700 // emission at the beginning of this method.
5701 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005702 break;
5703 }
5704 __ Bind(&done);
5705
Roland Levillain3b359c72015-11-17 19:35:12 +00005706 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005707}
5708
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005709void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5710 LocationSummary* locations =
5711 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5712 InvokeRuntimeCallingConvention calling_convention;
5713 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5714}
5715
5716void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5717 codegen_->InvokeRuntime(instruction->IsEnter()
5718 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5719 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005720 instruction->GetDexPc(),
5721 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005722 if (instruction->IsEnter()) {
5723 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5724 } else {
5725 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5726 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005727}
5728
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005729void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5730void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5731void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005732
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005733void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005734 LocationSummary* locations =
5735 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5736 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5737 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005738 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005739 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005740 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005741 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005742}
5743
5744void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5745 HandleBitwiseOperation(instruction);
5746}
5747
5748void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5749 HandleBitwiseOperation(instruction);
5750}
5751
5752void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5753 HandleBitwiseOperation(instruction);
5754}
5755
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005756void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5757 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5758 if (value == 0xffffffffu) {
5759 if (out != first) {
5760 __ mov(out, ShifterOperand(first));
5761 }
5762 return;
5763 }
5764 if (value == 0u) {
5765 __ mov(out, ShifterOperand(0));
5766 return;
5767 }
5768 ShifterOperand so;
5769 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5770 __ and_(out, first, so);
5771 } else {
5772 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5773 __ bic(out, first, ShifterOperand(~value));
5774 }
5775}
5776
5777void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5778 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5779 if (value == 0u) {
5780 if (out != first) {
5781 __ mov(out, ShifterOperand(first));
5782 }
5783 return;
5784 }
5785 if (value == 0xffffffffu) {
5786 __ mvn(out, ShifterOperand(0));
5787 return;
5788 }
5789 ShifterOperand so;
5790 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5791 __ orr(out, first, so);
5792 } else {
5793 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5794 __ orn(out, first, ShifterOperand(~value));
5795 }
5796}
5797
5798void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5799 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5800 if (value == 0u) {
5801 if (out != first) {
5802 __ mov(out, ShifterOperand(first));
5803 }
5804 return;
5805 }
5806 __ eor(out, first, ShifterOperand(value));
5807}
5808
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005809void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5810 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005811 Location first = locations->InAt(0);
5812 Location second = locations->InAt(1);
5813 Location out = locations->Out();
5814
5815 if (second.IsConstant()) {
5816 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5817 uint32_t value_low = Low32Bits(value);
5818 if (instruction->GetResultType() == Primitive::kPrimInt) {
5819 Register first_reg = first.AsRegister<Register>();
5820 Register out_reg = out.AsRegister<Register>();
5821 if (instruction->IsAnd()) {
5822 GenerateAndConst(out_reg, first_reg, value_low);
5823 } else if (instruction->IsOr()) {
5824 GenerateOrrConst(out_reg, first_reg, value_low);
5825 } else {
5826 DCHECK(instruction->IsXor());
5827 GenerateEorConst(out_reg, first_reg, value_low);
5828 }
5829 } else {
5830 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5831 uint32_t value_high = High32Bits(value);
5832 Register first_low = first.AsRegisterPairLow<Register>();
5833 Register first_high = first.AsRegisterPairHigh<Register>();
5834 Register out_low = out.AsRegisterPairLow<Register>();
5835 Register out_high = out.AsRegisterPairHigh<Register>();
5836 if (instruction->IsAnd()) {
5837 GenerateAndConst(out_low, first_low, value_low);
5838 GenerateAndConst(out_high, first_high, value_high);
5839 } else if (instruction->IsOr()) {
5840 GenerateOrrConst(out_low, first_low, value_low);
5841 GenerateOrrConst(out_high, first_high, value_high);
5842 } else {
5843 DCHECK(instruction->IsXor());
5844 GenerateEorConst(out_low, first_low, value_low);
5845 GenerateEorConst(out_high, first_high, value_high);
5846 }
5847 }
5848 return;
5849 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005850
5851 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005852 Register first_reg = first.AsRegister<Register>();
5853 ShifterOperand second_reg(second.AsRegister<Register>());
5854 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005855 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005856 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005857 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005858 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005859 } else {
5860 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005861 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005862 }
5863 } else {
5864 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005865 Register first_low = first.AsRegisterPairLow<Register>();
5866 Register first_high = first.AsRegisterPairHigh<Register>();
5867 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5868 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5869 Register out_low = out.AsRegisterPairLow<Register>();
5870 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005871 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005872 __ and_(out_low, first_low, second_low);
5873 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005874 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005875 __ orr(out_low, first_low, second_low);
5876 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005877 } else {
5878 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005879 __ eor(out_low, first_low, second_low);
5880 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005881 }
5882 }
5883}
5884
Roland Levillain3b359c72015-11-17 19:35:12 +00005885void CodeGeneratorARM::GenerateReadBarrier(HInstruction* instruction,
5886 Location out,
5887 Location ref,
5888 Location obj,
5889 uint32_t offset,
5890 Location index) {
5891 DCHECK(kEmitCompilerReadBarrier);
5892
5893 // If heap poisoning is enabled, the unpoisoning of the loaded
5894 // reference will be carried out by the runtime within the slow
5895 // path.
5896 //
5897 // Note that `ref` currently does not get unpoisoned (when heap
5898 // poisoning is enabled), which is alright as the `ref` argument is
5899 // not used by the artReadBarrierSlow entry point.
5900 //
5901 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
5902 SlowPathCode* slow_path = new (GetGraph()->GetArena())
5903 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
5904 AddSlowPath(slow_path);
5905
5906 // TODO: When read barrier has a fast path, add it here.
5907 /* Currently the read barrier call is inserted after the original load.
5908 * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the
5909 * original load. This load-load ordering is required by the read barrier.
5910 * The fast path/slow path (for Baker's algorithm) should look like:
5911 *
5912 * bool isGray = obj.LockWord & kReadBarrierMask;
5913 * lfence; // load fence or artificial data dependence to prevent load-load reordering
5914 * ref = obj.field; // this is the original load
5915 * if (isGray) {
5916 * ref = Mark(ref); // ideally the slow path just does Mark(ref)
5917 * }
5918 */
5919
5920 __ b(slow_path->GetEntryLabel());
5921 __ Bind(slow_path->GetExitLabel());
5922}
5923
5924void CodeGeneratorARM::MaybeGenerateReadBarrier(HInstruction* instruction,
5925 Location out,
5926 Location ref,
5927 Location obj,
5928 uint32_t offset,
5929 Location index) {
5930 if (kEmitCompilerReadBarrier) {
5931 // If heap poisoning is enabled, unpoisoning will be taken care of
5932 // by the runtime within the slow path.
5933 GenerateReadBarrier(instruction, out, ref, obj, offset, index);
5934 } else if (kPoisonHeapReferences) {
5935 __ UnpoisonHeapReference(out.AsRegister<Register>());
5936 }
5937}
5938
5939void CodeGeneratorARM::GenerateReadBarrierForRoot(HInstruction* instruction,
5940 Location out,
5941 Location root) {
5942 DCHECK(kEmitCompilerReadBarrier);
5943
5944 // Note that GC roots are not affected by heap poisoning, so we do
5945 // not need to do anything special for this here.
5946 SlowPathCode* slow_path =
5947 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
5948 AddSlowPath(slow_path);
5949
5950 // TODO: Implement a fast path for ReadBarrierForRoot, performing
5951 // the following operation (for Baker's algorithm):
5952 //
5953 // if (thread.tls32_.is_gc_marking) {
5954 // root = Mark(root);
5955 // }
5956
5957 __ b(slow_path->GetEntryLabel());
5958 __ Bind(slow_path->GetExitLabel());
5959}
5960
Vladimir Markodc151b22015-10-15 18:02:30 +01005961HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5962 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5963 MethodReference target_method) {
Vladimir Markodc151b22015-10-15 18:02:30 +01005964 if (desired_dispatch_info.code_ptr_location ==
5965 HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5966 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5967 if (&outer_dex_file != target_method.dex_file) {
5968 // Calls across dex files are more likely to exceed the available BL range,
5969 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5970 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5971 (desired_dispatch_info.method_load_kind ==
5972 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
5973 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
5974 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
5975 return HInvokeStaticOrDirect::DispatchInfo {
5976 desired_dispatch_info.method_load_kind,
5977 code_ptr_location,
5978 desired_dispatch_info.method_load_data,
5979 0u
5980 };
5981 }
5982 }
5983 return desired_dispatch_info;
5984}
5985
Vladimir Markob4536b72015-11-24 13:45:23 +00005986Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
5987 Register temp) {
5988 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
5989 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
5990 if (!invoke->GetLocations()->Intrinsified()) {
5991 return location.AsRegister<Register>();
5992 }
5993 // For intrinsics we allow any location, so it may be on the stack.
5994 if (!location.IsRegister()) {
5995 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
5996 return temp;
5997 }
5998 // For register locations, check if the register was saved. If so, get it from the stack.
5999 // Note: There is a chance that the register was saved but not overwritten, so we could
6000 // save one load. However, since this is just an intrinsic slow path we prefer this
6001 // simple and more robust approach rather that trying to determine if that's the case.
6002 SlowPathCode* slow_path = GetCurrentSlowPath();
6003 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6004 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6005 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6006 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6007 return temp;
6008 }
6009 return location.AsRegister<Register>();
6010}
6011
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006012void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006013 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006014 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006015 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6016 // LR = code address from literal pool with link-time patch.
6017 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006018 break;
6019 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6020 // LR = invoke->GetDirectCodePtr();
6021 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006022 break;
6023 default:
6024 break;
6025 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006026
Vladimir Marko58155012015-08-19 12:49:41 +00006027 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6028 switch (invoke->GetMethodLoadKind()) {
6029 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6030 // temp = thread->string_init_entrypoint
6031 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6032 break;
6033 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006034 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006035 break;
6036 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6037 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6038 break;
6039 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6040 __ LoadLiteral(temp.AsRegister<Register>(),
6041 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6042 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006043 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6044 HArmDexCacheArraysBase* base =
6045 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6046 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6047 temp.AsRegister<Register>());
6048 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6049 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6050 break;
6051 }
Vladimir Marko58155012015-08-19 12:49:41 +00006052 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006053 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006054 Register method_reg;
6055 Register reg = temp.AsRegister<Register>();
6056 if (current_method.IsRegister()) {
6057 method_reg = current_method.AsRegister<Register>();
6058 } else {
6059 DCHECK(invoke->GetLocations()->Intrinsified());
6060 DCHECK(!current_method.IsValid());
6061 method_reg = reg;
6062 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6063 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006064 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6065 __ LoadFromOffset(kLoadWord,
6066 reg,
6067 method_reg,
6068 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00006069 // temp = temp[index_in_cache]
6070 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
6071 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6072 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006073 }
Vladimir Marko58155012015-08-19 12:49:41 +00006074 }
6075
6076 switch (invoke->GetCodePtrLocation()) {
6077 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6078 __ bl(GetFrameEntryLabel());
6079 break;
6080 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006081 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006082 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006083 // Arbitrarily branch to the BL itself, override at link time.
6084 __ bl(&relative_call_patches_.back().label);
6085 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006086 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6087 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6088 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006089 // LR()
6090 __ blx(LR);
6091 break;
6092 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6093 // LR = callee_method->entry_point_from_quick_compiled_code_
6094 __ LoadFromOffset(
6095 kLoadWord, LR, callee_method.AsRegister<Register>(),
6096 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6097 // LR()
6098 __ blx(LR);
6099 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006100 }
6101
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006102 DCHECK(!IsLeafMethod());
6103}
6104
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006105void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6106 Register temp = temp_location.AsRegister<Register>();
6107 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6108 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006109
6110 // Use the calling convention instead of the location of the receiver, as
6111 // intrinsics may have put the receiver in a different register. In the intrinsics
6112 // slow path, the arguments have been moved to the right place, so here we are
6113 // guaranteed that the receiver is the first register of the calling convention.
6114 InvokeDexCallingConvention calling_convention;
6115 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006116 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006117 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006118 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006119 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006120 // Instead of simply (possibly) unpoisoning `temp` here, we should
6121 // emit a read barrier for the previous class reference load.
6122 // However this is not required in practice, as this is an
6123 // intermediate/temporary reference and because the current
6124 // concurrent copying collector keeps the from-space memory
6125 // intact/accessible until the end of the marking phase (the
6126 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006127 __ MaybeUnpoisonHeapReference(temp);
6128 // temp = temp->GetMethodAt(method_offset);
6129 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6130 kArmWordSize).Int32Value();
6131 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6132 // LR = temp->GetEntryPoint();
6133 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6134 // LR();
6135 __ blx(LR);
6136}
6137
Vladimir Marko58155012015-08-19 12:49:41 +00006138void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6139 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006140 size_t size =
6141 method_patches_.size() +
6142 call_patches_.size() +
6143 relative_call_patches_.size() +
6144 /* MOVW+MOVT for each base */ 2u * dex_cache_arrays_base_labels_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006145 linker_patches->reserve(size);
6146 for (const auto& entry : method_patches_) {
6147 const MethodReference& target_method = entry.first;
6148 Literal* literal = entry.second;
6149 DCHECK(literal->GetLabel()->IsBound());
6150 uint32_t literal_offset = literal->GetLabel()->Position();
6151 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6152 target_method.dex_file,
6153 target_method.dex_method_index));
6154 }
6155 for (const auto& entry : call_patches_) {
6156 const MethodReference& target_method = entry.first;
6157 Literal* literal = entry.second;
6158 DCHECK(literal->GetLabel()->IsBound());
6159 uint32_t literal_offset = literal->GetLabel()->Position();
6160 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6161 target_method.dex_file,
6162 target_method.dex_method_index));
6163 }
6164 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6165 uint32_t literal_offset = info.label.Position();
6166 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6167 info.target_method.dex_file,
6168 info.target_method.dex_method_index));
6169 }
Vladimir Markob4536b72015-11-24 13:45:23 +00006170 for (const auto& pair : dex_cache_arrays_base_labels_) {
6171 HArmDexCacheArraysBase* base = pair.first;
6172 const DexCacheArraysBaseLabels* labels = &pair.second;
6173 const DexFile& dex_file = base->GetDexFile();
6174 size_t base_element_offset = base->GetElementOffset();
6175 DCHECK(labels->add_pc_label.IsBound());
6176 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(labels->add_pc_label.Position());
6177 // Add MOVW patch.
6178 DCHECK(labels->movw_label.IsBound());
6179 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(labels->movw_label.Position());
6180 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6181 &dex_file,
6182 add_pc_offset,
6183 base_element_offset));
6184 // Add MOVT patch.
6185 DCHECK(labels->movt_label.IsBound());
6186 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(labels->movt_label.Position());
6187 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6188 &dex_file,
6189 add_pc_offset,
6190 base_element_offset));
6191 }
Vladimir Marko58155012015-08-19 12:49:41 +00006192}
6193
6194Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6195 MethodToLiteralMap* map) {
6196 // Look up the literal for target_method.
6197 auto lb = map->lower_bound(target_method);
6198 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
6199 return lb->second;
6200 }
6201 // We don't have a literal for this method yet, insert a new one.
6202 Literal* literal = __ NewLiteral<uint32_t>(0u);
6203 map->PutBefore(lb, target_method, literal);
6204 return literal;
6205}
6206
6207Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6208 return DeduplicateMethodLiteral(target_method, &method_patches_);
6209}
6210
6211Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6212 return DeduplicateMethodLiteral(target_method, &call_patches_);
6213}
6214
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006215void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006216 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006217 LOG(FATAL) << "Unreachable";
6218}
6219
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006220void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006221 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006222 LOG(FATAL) << "Unreachable";
6223}
6224
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01006225void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
6226 DCHECK(codegen_->IsBaseline());
6227 LocationSummary* locations =
6228 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6229 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
6230}
6231
6232void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
6233 DCHECK(codegen_->IsBaseline());
6234 // Will be generated at use site.
6235}
6236
Mark Mendellfe57faa2015-09-18 09:26:15 -04006237// Simple implementation of packed switch - generate cascaded compare/jumps.
6238void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6239 LocationSummary* locations =
6240 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6241 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006242 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006243 codegen_->GetAssembler()->IsThumb()) {
6244 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6245 if (switch_instr->GetStartValue() != 0) {
6246 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6247 }
6248 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006249}
6250
6251void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6252 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006253 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006254 LocationSummary* locations = switch_instr->GetLocations();
6255 Register value_reg = locations->InAt(0).AsRegister<Register>();
6256 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6257
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006258 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006259 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006260 Register temp_reg = IP;
6261 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6262 // the immediate, because IP is used as the destination register. For the other
6263 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6264 // and they can be encoded in the instruction without making use of IP register.
6265 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6266
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006267 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006268 // Jump to successors[0] if value == lower_bound.
6269 __ b(codegen_->GetLabelOf(successors[0]), EQ);
6270 int32_t last_index = 0;
6271 for (; num_entries - last_index > 2; last_index += 2) {
6272 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6273 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6274 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6275 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6276 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6277 }
6278 if (num_entries - last_index == 2) {
6279 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00006280 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006281 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006282 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006283
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006284 // And the default for any other value.
6285 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6286 __ b(codegen_->GetLabelOf(default_block));
6287 }
6288 } else {
6289 // Create a table lookup.
6290 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6291
6292 // Materialize a pointer to the switch table
6293 std::vector<Label*> labels(num_entries);
6294 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6295 for (uint32_t i = 0; i < num_entries; i++) {
6296 labels[i] = codegen_->GetLabelOf(successors[i]);
6297 }
6298 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6299
6300 // Remove the bias.
6301 Register key_reg;
6302 if (lower_bound != 0) {
6303 key_reg = locations->GetTemp(1).AsRegister<Register>();
6304 __ AddConstant(key_reg, value_reg, -lower_bound);
6305 } else {
6306 key_reg = value_reg;
6307 }
6308
6309 // Check whether the value is in the table, jump to default block if not.
6310 __ CmpConstant(key_reg, num_entries - 1);
6311 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6312
6313 // Load the displacement from the table.
6314 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6315
6316 // Dispatch is a direct add to the PC (for Thumb2).
6317 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006318 }
6319}
6320
Vladimir Markob4536b72015-11-24 13:45:23 +00006321void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6322 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6323 locations->SetOut(Location::RequiresRegister());
6324 codegen_->AddDexCacheArraysBase(base);
6325}
6326
6327void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6328 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
6329 CodeGeneratorARM::DexCacheArraysBaseLabels* labels = codegen_->GetDexCacheArraysBaseLabels(base);
6330 __ BindTrackedLabel(&labels->movw_label);
6331 __ movw(base_reg, 0u);
6332 __ BindTrackedLabel(&labels->movt_label);
6333 __ movt(base_reg, 0u);
6334 __ BindTrackedLabel(&labels->add_pc_label);
6335 __ add(base_reg, base_reg, ShifterOperand(PC));
6336}
6337
Andreas Gampe85b62f22015-09-09 13:15:38 -07006338void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6339 if (!trg.IsValid()) {
6340 DCHECK(type == Primitive::kPrimVoid);
6341 return;
6342 }
6343
6344 DCHECK_NE(type, Primitive::kPrimVoid);
6345
6346 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6347 if (return_loc.Equals(trg)) {
6348 return;
6349 }
6350
6351 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6352 // with the last branch.
6353 if (type == Primitive::kPrimLong) {
6354 HParallelMove parallel_move(GetGraph()->GetArena());
6355 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6356 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6357 GetMoveResolver()->EmitNativeCode(&parallel_move);
6358 } else if (type == Primitive::kPrimDouble) {
6359 HParallelMove parallel_move(GetGraph()->GetArena());
6360 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6361 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6362 GetMoveResolver()->EmitNativeCode(&parallel_move);
6363 } else {
6364 // Let the parallel move resolver take care of all of this.
6365 HParallelMove parallel_move(GetGraph()->GetArena());
6366 parallel_move.AddMove(return_loc, trg, type, nullptr);
6367 GetMoveResolver()->EmitNativeCode(&parallel_move);
6368 }
6369}
6370
Roland Levillain4d027112015-07-01 15:41:14 +01006371#undef __
6372#undef QUICK_ENTRY_POINT
6373
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006374} // namespace arm
6375} // namespace art