blob: e441f825bcc0d96ab22f1d918a402a3cd21a6d31 [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
David Brazdil58282f42016-01-14 12:45:10 +000050static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000051static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070052 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000053static constexpr SRegister kFpuCalleeSaves[] =
54 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010055
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000056// D31 cannot be split into two S registers, and the register allocator only works on
57// S registers. Therefore there is no need to block it.
58static constexpr DRegister DTMP = D31;
59
Vladimir Markof3e0ee22015-12-17 15:23:13 +000060static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070061
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -070062// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
63#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010064#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Andreas Gampe85b62f22015-09-09 13:15:38 -070066class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000068 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069
Alexandre Rames67555f72014-11-18 10:55:16 +000070 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010071 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000073 if (instruction_->CanThrowIntoCatchBlock()) {
74 // Live registers will be restored in the catch block if caught.
75 SaveLiveRegisters(codegen, instruction_->GetLocations());
76 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010077 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000078 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000079 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 }
81
Alexandre Rames8158f282015-08-07 10:26:17 +010082 bool IsFatal() const OVERRIDE { return true; }
83
Alexandre Rames9931f312015-06-19 14:47:01 +010084 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
85
Nicolas Geoffraye5038322014-07-04 09:41:32 +010086 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010087 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
88};
89
Andreas Gampe85b62f22015-09-09 13:15:38 -070090class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000091 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000092 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +000093
Alexandre Rames67555f72014-11-18 10:55:16 +000094 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000095 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
96 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000097 if (instruction_->CanThrowIntoCatchBlock()) {
98 // Live registers will be restored in the catch block if caught.
99 SaveLiveRegisters(codegen, instruction_->GetLocations());
100 }
Calin Juravled0d48522014-11-04 16:40:20 +0000101 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000102 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000103 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000104 }
105
Alexandre Rames8158f282015-08-07 10:26:17 +0100106 bool IsFatal() const OVERRIDE { return true; }
107
Alexandre Rames9931f312015-06-19 14:47:01 +0100108 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
109
Calin Juravled0d48522014-11-04 16:40:20 +0000110 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000111 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
112};
113
Andreas Gampe85b62f22015-09-09 13:15:38 -0700114class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000115 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000116 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000117 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118
Alexandre Rames67555f72014-11-18 10:55:16 +0000119 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100120 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000122 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100123 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000124 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000125 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000126 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100127 if (successor_ == nullptr) {
128 __ b(GetReturnLabel());
129 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100130 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100131 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 }
133
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 Label* GetReturnLabel() {
135 DCHECK(successor_ == nullptr);
136 return &return_label_;
137 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100139 HBasicBlock* GetSuccessor() const {
140 return successor_;
141 }
142
Alexandre Rames9931f312015-06-19 14:47:01 +0100143 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
144
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000145 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100146 // If not null, the block to branch to after the suspend check.
147 HBasicBlock* const successor_;
148
149 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000150 Label return_label_;
151
152 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
153};
154
Andreas Gampe85b62f22015-09-09 13:15:38 -0700155class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100157 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000158 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159
Alexandre Rames67555f72014-11-18 10:55:16 +0000160 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100161 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100162 LocationSummary* locations = instruction_->GetLocations();
163
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100164 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000165 if (instruction_->CanThrowIntoCatchBlock()) {
166 // Live registers will be restored in the catch block if caught.
167 SaveLiveRegisters(codegen, instruction_->GetLocations());
168 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000169 // We're moving two locations to locations that could overlap, so we need a parallel
170 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000172 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100173 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000174 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100175 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100176 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100177 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
178 Primitive::kPrimInt);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100179 uint32_t entry_point_offset = instruction_->AsBoundsCheck()->IsStringCharAt()
180 ? QUICK_ENTRY_POINT(pThrowStringBounds)
181 : QUICK_ENTRY_POINT(pThrowArrayBounds);
182 arm_codegen->InvokeRuntime(entry_point_offset, instruction_, instruction_->GetDexPc(), this);
183 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000184 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 }
186
Alexandre Rames8158f282015-08-07 10:26:17 +0100187 bool IsFatal() const OVERRIDE { return true; }
188
Alexandre Rames9931f312015-06-19 14:47:01 +0100189 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
190
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100191 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100192 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
193};
194
Andreas Gampe85b62f22015-09-09 13:15:38 -0700195class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100196 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197 LoadClassSlowPathARM(HLoadClass* cls,
198 HInstruction* at,
199 uint32_t dex_pc,
200 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000201 : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000202 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
203 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204
Alexandre Rames67555f72014-11-18 10:55:16 +0000205 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000206 LocationSummary* locations = at_->GetLocations();
207
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
209 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000210 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100211
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100212 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000214 int32_t entry_point_offset = do_clinit_
215 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
216 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000217 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000218 if (do_clinit_) {
219 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
220 } else {
221 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
222 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000223
224 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000225 Location out = locations->Out();
226 if (out.IsValid()) {
227 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000228 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
229 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000230 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100231 __ b(GetExitLabel());
232 }
233
Alexandre Rames9931f312015-06-19 14:47:01 +0100234 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
235
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100236 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 // The class this slow path will load.
238 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100239
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000240 // The instruction where this slow path is happening.
241 // (Might be the load class or an initialization check).
242 HInstruction* const at_;
243
244 // The dex PC of `at_`.
245 const uint32_t dex_pc_;
246
247 // Whether to initialize the class.
248 const bool do_clinit_;
249
250 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100251};
252
Andreas Gampe85b62f22015-09-09 13:15:38 -0700253class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000254 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000255 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000256
Alexandre Rames67555f72014-11-18 10:55:16 +0000257 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000258 LocationSummary* locations = instruction_->GetLocations();
259 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
260
261 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
262 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000263 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000264
265 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000266 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
267 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000268 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000269 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000270 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000271 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
272
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000273 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000274 __ b(GetExitLabel());
275 }
276
Alexandre Rames9931f312015-06-19 14:47:01 +0100277 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
278
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000279 private:
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000280 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
281};
282
Andreas Gampe85b62f22015-09-09 13:15:38 -0700283class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000285 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000286 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000287
Alexandre Rames67555f72014-11-18 10:55:16 +0000288 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000289 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100290 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
291 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000292 DCHECK(instruction_->IsCheckCast()
293 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294
295 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
296 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000297
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000298 if (!is_fatal_) {
299 SaveLiveRegisters(codegen, locations);
300 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000301
302 // We're moving two locations to locations that could overlap, so we need a parallel
303 // move resolver.
304 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000305 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100306 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000307 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100308 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100309 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100310 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
311 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000312
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000313 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100314 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
315 instruction_,
316 instruction_->GetDexPc(),
317 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000318 CheckEntrypointTypes<
319 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000320 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
321 } else {
322 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100323 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
324 instruction_,
325 instruction_->GetDexPc(),
326 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000327 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000328 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000329
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000330 if (!is_fatal_) {
331 RestoreLiveRegisters(codegen, locations);
332 __ b(GetExitLabel());
333 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000334 }
335
Alexandre Rames9931f312015-06-19 14:47:01 +0100336 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
337
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000338 bool IsFatal() const OVERRIDE { return is_fatal_; }
339
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000341 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000342
343 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
344};
345
Andreas Gampe85b62f22015-09-09 13:15:38 -0700346class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700347 public:
Aart Bik42249c32016-01-07 15:33:50 -0800348 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000349 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700350
351 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800352 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700353 __ Bind(GetEntryLabel());
354 SaveLiveRegisters(codegen, instruction_->GetLocations());
Aart Bik42249c32016-01-07 15:33:50 -0800355 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
356 instruction_,
357 instruction_->GetDexPc(),
358 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000359 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700360 }
361
Alexandre Rames9931f312015-06-19 14:47:01 +0100362 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
363
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700364 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700365 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
366};
367
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100368class ArraySetSlowPathARM : public SlowPathCode {
369 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000370 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100371
372 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
373 LocationSummary* locations = instruction_->GetLocations();
374 __ Bind(GetEntryLabel());
375 SaveLiveRegisters(codegen, locations);
376
377 InvokeRuntimeCallingConvention calling_convention;
378 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
379 parallel_move.AddMove(
380 locations->InAt(0),
381 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
382 Primitive::kPrimNot,
383 nullptr);
384 parallel_move.AddMove(
385 locations->InAt(1),
386 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
387 Primitive::kPrimInt,
388 nullptr);
389 parallel_move.AddMove(
390 locations->InAt(2),
391 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
392 Primitive::kPrimNot,
393 nullptr);
394 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
395
396 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
397 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
398 instruction_,
399 instruction_->GetDexPc(),
400 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000401 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100402 RestoreLiveRegisters(codegen, locations);
403 __ b(GetExitLabel());
404 }
405
406 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
407
408 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100409 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
410};
411
Roland Levillainc9285912015-12-18 10:38:42 +0000412// Slow path marking an object during a read barrier.
413class ReadBarrierMarkSlowPathARM : public SlowPathCode {
414 public:
415 ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location out, Location obj)
David Srbecky9cd6d372016-02-09 15:24:47 +0000416 : SlowPathCode(instruction), out_(out), obj_(obj) {
Roland Levillainc9285912015-12-18 10:38:42 +0000417 DCHECK(kEmitCompilerReadBarrier);
418 }
419
420 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
421
422 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
423 LocationSummary* locations = instruction_->GetLocations();
424 Register reg_out = out_.AsRegister<Register>();
425 DCHECK(locations->CanCall());
426 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
427 DCHECK(instruction_->IsInstanceFieldGet() ||
428 instruction_->IsStaticFieldGet() ||
429 instruction_->IsArrayGet() ||
430 instruction_->IsLoadClass() ||
431 instruction_->IsLoadString() ||
432 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100433 instruction_->IsCheckCast() ||
434 ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
435 instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +0000436 << "Unexpected instruction in read barrier marking slow path: "
437 << instruction_->DebugName();
438
439 __ Bind(GetEntryLabel());
440 SaveLiveRegisters(codegen, locations);
441
442 InvokeRuntimeCallingConvention calling_convention;
443 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
444 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
445 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
446 instruction_,
447 instruction_->GetDexPc(),
448 this);
449 CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
450 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
451
452 RestoreLiveRegisters(codegen, locations);
453 __ b(GetExitLabel());
454 }
455
456 private:
Roland Levillainc9285912015-12-18 10:38:42 +0000457 const Location out_;
458 const Location obj_;
459
460 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
461};
462
Roland Levillain3b359c72015-11-17 19:35:12 +0000463// Slow path generating a read barrier for a heap reference.
464class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
465 public:
466 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
467 Location out,
468 Location ref,
469 Location obj,
470 uint32_t offset,
471 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000472 : SlowPathCode(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000473 out_(out),
474 ref_(ref),
475 obj_(obj),
476 offset_(offset),
477 index_(index) {
478 DCHECK(kEmitCompilerReadBarrier);
479 // If `obj` is equal to `out` or `ref`, it means the initial object
480 // has been overwritten by (or after) the heap object reference load
481 // to be instrumented, e.g.:
482 //
483 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000484 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000485 //
486 // In that case, we have lost the information about the original
487 // object, and the emitted read barrier cannot work properly.
488 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
489 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
490 }
491
492 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
493 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
494 LocationSummary* locations = instruction_->GetLocations();
495 Register reg_out = out_.AsRegister<Register>();
496 DCHECK(locations->CanCall());
497 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +0100498 DCHECK(instruction_->IsInstanceFieldGet() ||
499 instruction_->IsStaticFieldGet() ||
500 instruction_->IsArrayGet() ||
501 instruction_->IsInstanceOf() ||
502 instruction_->IsCheckCast() ||
503 ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
Roland Levillainc9285912015-12-18 10:38:42 +0000504 instruction_->GetLocations()->Intrinsified()))
505 << "Unexpected instruction in read barrier for heap reference slow path: "
506 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000507
508 __ Bind(GetEntryLabel());
509 SaveLiveRegisters(codegen, locations);
510
511 // We may have to change the index's value, but as `index_` is a
512 // constant member (like other "inputs" of this slow path),
513 // introduce a copy of it, `index`.
514 Location index = index_;
515 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100516 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +0000517 if (instruction_->IsArrayGet()) {
518 // Compute the actual memory offset and store it in `index`.
519 Register index_reg = index_.AsRegister<Register>();
520 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
521 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
522 // We are about to change the value of `index_reg` (see the
523 // calls to art::arm::Thumb2Assembler::Lsl and
524 // art::arm::Thumb2Assembler::AddConstant below), but it has
525 // not been saved by the previous call to
526 // art::SlowPathCode::SaveLiveRegisters, as it is a
527 // callee-save register --
528 // art::SlowPathCode::SaveLiveRegisters does not consider
529 // callee-save registers, as it has been designed with the
530 // assumption that callee-save registers are supposed to be
531 // handled by the called function. So, as a callee-save
532 // register, `index_reg` _would_ eventually be saved onto
533 // the stack, but it would be too late: we would have
534 // changed its value earlier. Therefore, we manually save
535 // it here into another freely available register,
536 // `free_reg`, chosen of course among the caller-save
537 // registers (as a callee-save `free_reg` register would
538 // exhibit the same problem).
539 //
540 // Note we could have requested a temporary register from
541 // the register allocator instead; but we prefer not to, as
542 // this is a slow path, and we know we can find a
543 // caller-save register that is available.
544 Register free_reg = FindAvailableCallerSaveRegister(codegen);
545 __ Mov(free_reg, index_reg);
546 index_reg = free_reg;
547 index = Location::RegisterLocation(index_reg);
548 } else {
549 // The initial register stored in `index_` has already been
550 // saved in the call to art::SlowPathCode::SaveLiveRegisters
551 // (as it is not a callee-save register), so we can freely
552 // use it.
553 }
554 // Shifting the index value contained in `index_reg` by the scale
555 // factor (2) cannot overflow in practice, as the runtime is
556 // unable to allocate object arrays with a size larger than
557 // 2^26 - 1 (that is, 2^28 - 4 bytes).
558 __ Lsl(index_reg, index_reg, TIMES_4);
559 static_assert(
560 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
561 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
562 __ AddConstant(index_reg, index_reg, offset_);
563 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100564 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
565 // intrinsics, `index_` is not shifted by a scale factor of 2
566 // (as in the case of ArrayGet), as it is actually an offset
567 // to an object field within an object.
568 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000569 DCHECK(instruction_->GetLocations()->Intrinsified());
570 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
571 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
572 << instruction_->AsInvoke()->GetIntrinsic();
573 DCHECK_EQ(offset_, 0U);
574 DCHECK(index_.IsRegisterPair());
575 // UnsafeGet's offset location is a register pair, the low
576 // part contains the correct offset.
577 index = index_.ToLow();
578 }
579 }
580
581 // We're moving two or three locations to locations that could
582 // overlap, so we need a parallel move resolver.
583 InvokeRuntimeCallingConvention calling_convention;
584 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
585 parallel_move.AddMove(ref_,
586 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
587 Primitive::kPrimNot,
588 nullptr);
589 parallel_move.AddMove(obj_,
590 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
591 Primitive::kPrimNot,
592 nullptr);
593 if (index.IsValid()) {
594 parallel_move.AddMove(index,
595 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
596 Primitive::kPrimInt,
597 nullptr);
598 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
599 } else {
600 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
601 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
602 }
603 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
604 instruction_,
605 instruction_->GetDexPc(),
606 this);
607 CheckEntrypointTypes<
608 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
609 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
610
611 RestoreLiveRegisters(codegen, locations);
612 __ b(GetExitLabel());
613 }
614
615 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
616
617 private:
618 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
619 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
620 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
621 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
622 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
623 return static_cast<Register>(i);
624 }
625 }
626 // We shall never fail to find a free caller-save register, as
627 // there are more than two core caller-save registers on ARM
628 // (meaning it is possible to find one which is different from
629 // `ref` and `obj`).
630 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
631 LOG(FATAL) << "Could not find a free caller-save register";
632 UNREACHABLE();
633 }
634
Roland Levillain3b359c72015-11-17 19:35:12 +0000635 const Location out_;
636 const Location ref_;
637 const Location obj_;
638 const uint32_t offset_;
639 // An additional location containing an index to an array.
640 // Only used for HArrayGet and the UnsafeGetObject &
641 // UnsafeGetObjectVolatile intrinsics.
642 const Location index_;
643
644 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
645};
646
647// Slow path generating a read barrier for a GC root.
648class ReadBarrierForRootSlowPathARM : public SlowPathCode {
649 public:
650 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000651 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +0000652 DCHECK(kEmitCompilerReadBarrier);
653 }
Roland Levillain3b359c72015-11-17 19:35:12 +0000654
655 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
656 LocationSummary* locations = instruction_->GetLocations();
657 Register reg_out = out_.AsRegister<Register>();
658 DCHECK(locations->CanCall());
659 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +0000660 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
661 << "Unexpected instruction in read barrier for GC root slow path: "
662 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000663
664 __ Bind(GetEntryLabel());
665 SaveLiveRegisters(codegen, locations);
666
667 InvokeRuntimeCallingConvention calling_convention;
668 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
669 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
670 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
671 instruction_,
672 instruction_->GetDexPc(),
673 this);
674 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
675 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
676
677 RestoreLiveRegisters(codegen, locations);
678 __ b(GetExitLabel());
679 }
680
681 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
682
683 private:
Roland Levillain3b359c72015-11-17 19:35:12 +0000684 const Location out_;
685 const Location root_;
686
687 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
688};
689
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000690#undef __
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -0700691// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
692#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
Dave Allison20dfc792014-06-16 20:44:29 -0700693
Aart Bike9f37602015-10-09 11:15:55 -0700694inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700695 switch (cond) {
696 case kCondEQ: return EQ;
697 case kCondNE: return NE;
698 case kCondLT: return LT;
699 case kCondLE: return LE;
700 case kCondGT: return GT;
701 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700702 case kCondB: return LO;
703 case kCondBE: return LS;
704 case kCondA: return HI;
705 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700706 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100707 LOG(FATAL) << "Unreachable";
708 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700709}
710
Aart Bike9f37602015-10-09 11:15:55 -0700711// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100712inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700713 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100714 case kCondEQ: return EQ;
715 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700716 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100717 case kCondLT: return LO;
718 case kCondLE: return LS;
719 case kCondGT: return HI;
720 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700721 // Unsigned remain unchanged.
722 case kCondB: return LO;
723 case kCondBE: return LS;
724 case kCondA: return HI;
725 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700726 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100727 LOG(FATAL) << "Unreachable";
728 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700729}
730
Vladimir Markod6e069b2016-01-18 11:11:01 +0000731inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
732 // The ARM condition codes can express all the necessary branches, see the
733 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
734 // There is no dex instruction or HIR that would need the missing conditions
735 // "equal or unordered" or "not equal".
736 switch (cond) {
737 case kCondEQ: return EQ;
738 case kCondNE: return NE /* unordered */;
739 case kCondLT: return gt_bias ? CC : LT /* unordered */;
740 case kCondLE: return gt_bias ? LS : LE /* unordered */;
741 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
742 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
743 default:
744 LOG(FATAL) << "UNREACHABLE";
745 UNREACHABLE();
746 }
747}
748
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100749void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100750 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100751}
752
753void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100754 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100755}
756
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100757size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
758 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
759 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100760}
761
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100762size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
763 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
764 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100765}
766
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000767size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
768 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
769 return kArmWordSize;
770}
771
772size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
773 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
774 return kArmWordSize;
775}
776
Calin Juravle34166012014-12-19 17:22:29 +0000777CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000778 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100779 const CompilerOptions& compiler_options,
780 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000781 : CodeGenerator(graph,
782 kNumberOfCoreRegisters,
783 kNumberOfSRegisters,
784 kNumberOfRegisterPairs,
785 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
786 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000787 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
788 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100789 compiler_options,
790 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100791 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100792 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100793 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100794 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100795 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +0000796 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000797 uint32_literals_(std::less<uint32_t>(),
798 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko5233f932015-09-29 19:01:15 +0100799 method_patches_(MethodReferenceComparator(),
800 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
801 call_patches_(MethodReferenceComparator(),
802 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000803 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000804 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
805 boot_image_string_patches_(StringReferenceValueComparator(),
806 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
807 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100808 boot_image_type_patches_(TypeReferenceValueComparator(),
809 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
810 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000811 boot_image_address_patches_(std::less<uint32_t>(),
812 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700813 // Always save the LR register to mimic Quick.
814 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100815}
816
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000817void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
818 // Ensure that we fix up branches and literal loads and emit the literal pool.
819 __ FinalizeCode();
820
821 // Adjust native pc offsets in stack maps.
822 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
823 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
824 uint32_t new_position = __ GetAdjustedPosition(old_position);
825 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
826 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100827 // Adjust pc offsets for the disassembly information.
828 if (disasm_info_ != nullptr) {
829 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
830 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
831 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
832 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
833 it.second.start = __ GetAdjustedPosition(it.second.start);
834 it.second.end = __ GetAdjustedPosition(it.second.end);
835 }
836 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
837 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
838 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
839 }
840 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000841
842 CodeGenerator::Finalize(allocator);
843}
844
David Brazdil58282f42016-01-14 12:45:10 +0000845void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100846 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100847 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100848
849 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100850 blocked_core_registers_[SP] = true;
851 blocked_core_registers_[LR] = true;
852 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100853
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100854 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100855 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100856
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100857 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100858 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100859
David Brazdil58282f42016-01-14 12:45:10 +0000860 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100861 // Stubs do not save callee-save floating point registers. If the graph
862 // is debuggable, we need to deal with these registers differently. For
863 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000864 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
865 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
866 }
867 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100868
869 UpdateBlockedPairRegisters();
870}
871
872void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
873 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
874 ArmManagedRegister current =
875 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
876 if (blocked_core_registers_[current.AsRegisterPairLow()]
877 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
878 blocked_register_pairs_[i] = true;
879 }
880 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100881}
882
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100883InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -0800884 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100885 assembler_(codegen->GetAssembler()),
886 codegen_(codegen) {}
887
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000888void CodeGeneratorARM::ComputeSpillMask() {
889 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
890 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +0000891 // There is no easy instruction to restore just the PC on thumb2. We spill and
892 // restore another arbitrary register.
893 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000894 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
895 // We use vpush and vpop for saving and restoring floating point registers, which take
896 // a SRegister and the number of registers to save/restore after that SRegister. We
897 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
898 // but in the range.
899 if (fpu_spill_mask_ != 0) {
900 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
901 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
902 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
903 fpu_spill_mask_ |= (1 << i);
904 }
905 }
906}
907
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100908static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100909 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100910}
911
912static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100913 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100914}
915
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000916void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000917 bool skip_overflow_check =
918 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000919 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000920 __ Bind(&frame_entry_label_);
921
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000922 if (HasEmptyFrame()) {
923 return;
924 }
925
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100926 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000927 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
928 __ LoadFromOffset(kLoadWord, IP, IP, 0);
929 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100930 }
931
Andreas Gampe501fd632015-09-10 16:11:06 -0700932 __ PushList(core_spill_mask_);
933 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
934 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000935 if (fpu_spill_mask_ != 0) {
936 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
937 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100938 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100939 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000940 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100941 int adjust = GetFrameSize() - FrameEntrySpillSize();
942 __ AddConstant(SP, -adjust);
943 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100944 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000945}
946
947void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000948 if (HasEmptyFrame()) {
949 __ bx(LR);
950 return;
951 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100952 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100953 int adjust = GetFrameSize() - FrameEntrySpillSize();
954 __ AddConstant(SP, adjust);
955 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000956 if (fpu_spill_mask_ != 0) {
957 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
958 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100959 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
960 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000961 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700962 // Pop LR into PC to return.
963 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
964 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
965 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100966 __ cfi().RestoreState();
967 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000968}
969
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100970void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700971 Label* label = GetLabelOf(block);
972 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000973}
974
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100975Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100976 switch (type) {
977 case Primitive::kPrimBoolean:
978 case Primitive::kPrimByte:
979 case Primitive::kPrimChar:
980 case Primitive::kPrimShort:
981 case Primitive::kPrimInt:
982 case Primitive::kPrimNot: {
983 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000984 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100985 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100986 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100987 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000988 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100989 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100990 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100991
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000992 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100993 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000994 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100995 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000996 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100997 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000998 if (calling_convention.GetRegisterAt(index) == R1) {
999 // Skip R1, and use R2_R3 instead.
1000 gp_index_++;
1001 index++;
1002 }
1003 }
1004 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1005 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001006 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001007
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001008 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001009 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001010 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001011 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1012 }
1013 }
1014
1015 case Primitive::kPrimFloat: {
1016 uint32_t stack_index = stack_index_++;
1017 if (float_index_ % 2 == 0) {
1018 float_index_ = std::max(double_index_, float_index_);
1019 }
1020 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1021 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1022 } else {
1023 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1024 }
1025 }
1026
1027 case Primitive::kPrimDouble: {
1028 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1029 uint32_t stack_index = stack_index_;
1030 stack_index_ += 2;
1031 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1032 uint32_t index = double_index_;
1033 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001034 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001035 calling_convention.GetFpuRegisterAt(index),
1036 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001037 DCHECK(ExpectedPairLayout(result));
1038 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001039 } else {
1040 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001041 }
1042 }
1043
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001044 case Primitive::kPrimVoid:
1045 LOG(FATAL) << "Unexpected parameter type " << type;
1046 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001047 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001048 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001049}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001050
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001051Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001052 switch (type) {
1053 case Primitive::kPrimBoolean:
1054 case Primitive::kPrimByte:
1055 case Primitive::kPrimChar:
1056 case Primitive::kPrimShort:
1057 case Primitive::kPrimInt:
1058 case Primitive::kPrimNot: {
1059 return Location::RegisterLocation(R0);
1060 }
1061
1062 case Primitive::kPrimFloat: {
1063 return Location::FpuRegisterLocation(S0);
1064 }
1065
1066 case Primitive::kPrimLong: {
1067 return Location::RegisterPairLocation(R0, R1);
1068 }
1069
1070 case Primitive::kPrimDouble: {
1071 return Location::FpuRegisterPairLocation(S0, S1);
1072 }
1073
1074 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001075 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001076 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001077
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001078 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001079}
1080
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001081Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1082 return Location::RegisterLocation(kMethodRegisterArgument);
1083}
1084
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001085void CodeGeneratorARM::Move32(Location destination, Location source) {
1086 if (source.Equals(destination)) {
1087 return;
1088 }
1089 if (destination.IsRegister()) {
1090 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001091 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001092 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001093 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001094 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001095 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001096 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001097 } else if (destination.IsFpuRegister()) {
1098 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001099 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001100 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001101 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001102 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001103 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001104 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001105 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001106 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001107 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001108 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001109 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001110 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001111 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001112 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001113 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1114 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 }
1116 }
1117}
1118
1119void CodeGeneratorARM::Move64(Location destination, Location source) {
1120 if (source.Equals(destination)) {
1121 return;
1122 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001123 if (destination.IsRegisterPair()) {
1124 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001125 EmitParallelMoves(
1126 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1127 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001128 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001129 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001130 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1131 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001132 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001133 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001134 } else if (source.IsFpuRegisterPair()) {
1135 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1136 destination.AsRegisterPairHigh<Register>(),
1137 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001138 } else {
1139 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001140 DCHECK(ExpectedPairLayout(destination));
1141 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1142 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001143 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001144 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001145 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001146 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1147 SP,
1148 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001149 } else if (source.IsRegisterPair()) {
1150 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1151 source.AsRegisterPairLow<Register>(),
1152 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001153 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001154 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001155 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001156 } else {
1157 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001158 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001159 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001160 if (source.AsRegisterPairLow<Register>() == R1) {
1161 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001162 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1163 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001164 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001165 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001166 SP, destination.GetStackIndex());
1167 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001168 } else if (source.IsFpuRegisterPair()) {
1169 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1170 SP,
1171 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001172 } else {
1173 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001174 EmitParallelMoves(
1175 Location::StackSlot(source.GetStackIndex()),
1176 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001177 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001178 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001179 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1180 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001181 }
1182 }
1183}
1184
Calin Juravle175dc732015-08-25 15:42:32 +01001185void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1186 DCHECK(location.IsRegister());
1187 __ LoadImmediate(location.AsRegister<Register>(), value);
1188}
1189
Calin Juravlee460d1d2015-09-29 04:52:17 +01001190void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001191 HParallelMove move(GetGraph()->GetArena());
1192 move.AddMove(src, dst, dst_type, nullptr);
1193 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001194}
1195
1196void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1197 if (location.IsRegister()) {
1198 locations->AddTemp(location);
1199 } else if (location.IsRegisterPair()) {
1200 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1201 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1202 } else {
1203 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1204 }
1205}
1206
Calin Juravle175dc732015-08-25 15:42:32 +01001207void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1208 HInstruction* instruction,
1209 uint32_t dex_pc,
1210 SlowPathCode* slow_path) {
1211 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1212 instruction,
1213 dex_pc,
1214 slow_path);
1215}
1216
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001217void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1218 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001219 uint32_t dex_pc,
1220 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001221 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001222 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1223 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001224 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001225}
1226
David Brazdilfc6a86a2015-06-26 10:33:45 +00001227void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001228 DCHECK(!successor->IsExitBlock());
1229
1230 HBasicBlock* block = got->GetBlock();
1231 HInstruction* previous = got->GetPrevious();
1232
1233 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001234 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001235 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1236 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1237 return;
1238 }
1239
1240 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1241 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1242 }
1243 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001244 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001245 }
1246}
1247
David Brazdilfc6a86a2015-06-26 10:33:45 +00001248void LocationsBuilderARM::VisitGoto(HGoto* got) {
1249 got->SetLocations(nullptr);
1250}
1251
1252void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1253 HandleGoto(got, got->GetSuccessor());
1254}
1255
1256void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1257 try_boundary->SetLocations(nullptr);
1258}
1259
1260void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1261 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1262 if (!successor->IsExitBlock()) {
1263 HandleGoto(try_boundary, successor);
1264 }
1265}
1266
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001267void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001268 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001269}
1270
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001271void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001272}
1273
Roland Levillain4fa13f62015-07-06 18:11:54 +01001274void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1275 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001276 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001277 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001278 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001279}
1280
1281void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1282 Label* true_label,
1283 Label* false_label) {
1284 LocationSummary* locations = cond->GetLocations();
1285 Location left = locations->InAt(0);
1286 Location right = locations->InAt(1);
1287 IfCondition if_cond = cond->GetCondition();
1288
1289 Register left_high = left.AsRegisterPairHigh<Register>();
1290 Register left_low = left.AsRegisterPairLow<Register>();
1291 IfCondition true_high_cond = if_cond;
1292 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001293 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001294
1295 // Set the conditions for the test, remembering that == needs to be
1296 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001297 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001298 switch (if_cond) {
1299 case kCondEQ:
1300 case kCondNE:
1301 // Nothing to do.
1302 break;
1303 case kCondLT:
1304 false_high_cond = kCondGT;
1305 break;
1306 case kCondLE:
1307 true_high_cond = kCondLT;
1308 break;
1309 case kCondGT:
1310 false_high_cond = kCondLT;
1311 break;
1312 case kCondGE:
1313 true_high_cond = kCondGT;
1314 break;
Aart Bike9f37602015-10-09 11:15:55 -07001315 case kCondB:
1316 false_high_cond = kCondA;
1317 break;
1318 case kCondBE:
1319 true_high_cond = kCondB;
1320 break;
1321 case kCondA:
1322 false_high_cond = kCondB;
1323 break;
1324 case kCondAE:
1325 true_high_cond = kCondA;
1326 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001327 }
1328 if (right.IsConstant()) {
1329 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1330 int32_t val_low = Low32Bits(value);
1331 int32_t val_high = High32Bits(value);
1332
Vladimir Markoac6ac102015-12-17 12:14:00 +00001333 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001334 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001335 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001336 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001337 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001338 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001339 __ b(true_label, ARMCondition(true_high_cond));
1340 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001341 }
1342 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001343 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001344 } else {
1345 Register right_high = right.AsRegisterPairHigh<Register>();
1346 Register right_low = right.AsRegisterPairLow<Register>();
1347
1348 __ cmp(left_high, ShifterOperand(right_high));
1349 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001350 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001351 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001352 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001353 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001354 __ b(true_label, ARMCondition(true_high_cond));
1355 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001356 }
1357 // Must be equal high, so compare the lows.
1358 __ cmp(left_low, ShifterOperand(right_low));
1359 }
1360 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001361 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001362 __ b(true_label, final_condition);
1363}
1364
David Brazdil0debae72015-11-12 18:37:00 +00001365void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1366 Label* true_target_in,
1367 Label* false_target_in) {
1368 // Generated branching requires both targets to be explicit. If either of the
1369 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1370 Label fallthrough_target;
1371 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1372 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1373
Roland Levillain4fa13f62015-07-06 18:11:54 +01001374 LocationSummary* locations = condition->GetLocations();
1375 Location left = locations->InAt(0);
1376 Location right = locations->InAt(1);
1377
Roland Levillain4fa13f62015-07-06 18:11:54 +01001378 Primitive::Type type = condition->InputAt(0)->GetType();
1379 switch (type) {
1380 case Primitive::kPrimLong:
1381 GenerateLongComparesAndJumps(condition, true_target, false_target);
1382 break;
1383 case Primitive::kPrimFloat:
1384 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1385 GenerateFPJumps(condition, true_target, false_target);
1386 break;
1387 case Primitive::kPrimDouble:
1388 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1389 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1390 GenerateFPJumps(condition, true_target, false_target);
1391 break;
1392 default:
1393 LOG(FATAL) << "Unexpected compare type " << type;
1394 }
1395
David Brazdil0debae72015-11-12 18:37:00 +00001396 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001397 __ b(false_target);
1398 }
David Brazdil0debae72015-11-12 18:37:00 +00001399
1400 if (fallthrough_target.IsLinked()) {
1401 __ Bind(&fallthrough_target);
1402 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001403}
1404
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001405void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001406 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001407 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001408 Label* false_target) {
1409 HInstruction* cond = instruction->InputAt(condition_input_index);
1410
1411 if (true_target == nullptr && false_target == nullptr) {
1412 // Nothing to do. The code always falls through.
1413 return;
1414 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001415 // Constant condition, statically compared against "true" (integer value 1).
1416 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001417 if (true_target != nullptr) {
1418 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001419 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001420 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001421 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001422 if (false_target != nullptr) {
1423 __ b(false_target);
1424 }
1425 }
1426 return;
1427 }
1428
1429 // The following code generates these patterns:
1430 // (1) true_target == nullptr && false_target != nullptr
1431 // - opposite condition true => branch to false_target
1432 // (2) true_target != nullptr && false_target == nullptr
1433 // - condition true => branch to true_target
1434 // (3) true_target != nullptr && false_target != nullptr
1435 // - condition true => branch to true_target
1436 // - branch to false_target
1437 if (IsBooleanValueOrMaterializedCondition(cond)) {
1438 // Condition has been materialized, compare the output to 0.
1439 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1440 DCHECK(cond_val.IsRegister());
1441 if (true_target == nullptr) {
1442 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1443 } else {
1444 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001445 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001446 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001447 // Condition has not been materialized. Use its inputs as the comparison and
1448 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001449 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001450
1451 // If this is a long or FP comparison that has been folded into
1452 // the HCondition, generate the comparison directly.
1453 Primitive::Type type = condition->InputAt(0)->GetType();
1454 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1455 GenerateCompareTestAndBranch(condition, true_target, false_target);
1456 return;
1457 }
1458
1459 LocationSummary* locations = cond->GetLocations();
1460 DCHECK(locations->InAt(0).IsRegister());
1461 Register left = locations->InAt(0).AsRegister<Register>();
1462 Location right = locations->InAt(1);
1463 if (right.IsRegister()) {
1464 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001465 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001466 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001467 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001468 }
1469 if (true_target == nullptr) {
1470 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1471 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001472 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001473 }
Dave Allison20dfc792014-06-16 20:44:29 -07001474 }
David Brazdil0debae72015-11-12 18:37:00 +00001475
1476 // If neither branch falls through (case 3), the conditional branch to `true_target`
1477 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1478 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001479 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001480 }
1481}
1482
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001483void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001484 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1485 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001486 locations->SetInAt(0, Location::RequiresRegister());
1487 }
1488}
1489
1490void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001491 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1492 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1493 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1494 nullptr : codegen_->GetLabelOf(true_successor);
1495 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1496 nullptr : codegen_->GetLabelOf(false_successor);
1497 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001498}
1499
1500void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1501 LocationSummary* locations = new (GetGraph()->GetArena())
1502 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001503 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001504 locations->SetInAt(0, Location::RequiresRegister());
1505 }
1506}
1507
1508void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001509 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001510 GenerateTestAndBranch(deoptimize,
1511 /* condition_input_index */ 0,
1512 slow_path->GetEntryLabel(),
1513 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001514}
Dave Allison20dfc792014-06-16 20:44:29 -07001515
David Brazdil74eb1b22015-12-14 11:44:01 +00001516void LocationsBuilderARM::VisitSelect(HSelect* select) {
1517 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1518 if (Primitive::IsFloatingPointType(select->GetType())) {
1519 locations->SetInAt(0, Location::RequiresFpuRegister());
1520 locations->SetInAt(1, Location::RequiresFpuRegister());
1521 } else {
1522 locations->SetInAt(0, Location::RequiresRegister());
1523 locations->SetInAt(1, Location::RequiresRegister());
1524 }
1525 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1526 locations->SetInAt(2, Location::RequiresRegister());
1527 }
1528 locations->SetOut(Location::SameAsFirstInput());
1529}
1530
1531void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1532 LocationSummary* locations = select->GetLocations();
1533 Label false_target;
1534 GenerateTestAndBranch(select,
1535 /* condition_input_index */ 2,
1536 /* true_target */ nullptr,
1537 &false_target);
1538 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1539 __ Bind(&false_target);
1540}
1541
David Srbecky0cf44932015-12-09 14:09:59 +00001542void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1543 new (GetGraph()->GetArena()) LocationSummary(info);
1544}
1545
David Srbeckyd28f4a02016-03-14 17:14:24 +00001546void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
1547 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001548}
1549
1550void CodeGeneratorARM::GenerateNop() {
1551 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001552}
1553
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001554void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001555 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001556 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001557 // Handle the long/FP comparisons made in instruction simplification.
1558 switch (cond->InputAt(0)->GetType()) {
1559 case Primitive::kPrimLong:
1560 locations->SetInAt(0, Location::RequiresRegister());
1561 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001562 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001563 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1564 }
1565 break;
1566
1567 case Primitive::kPrimFloat:
1568 case Primitive::kPrimDouble:
1569 locations->SetInAt(0, Location::RequiresFpuRegister());
1570 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00001571 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001572 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1573 }
1574 break;
1575
1576 default:
1577 locations->SetInAt(0, Location::RequiresRegister());
1578 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001579 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001580 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1581 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001582 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001583}
1584
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001585void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001586 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001587 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001588 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001589
1590 LocationSummary* locations = cond->GetLocations();
1591 Location left = locations->InAt(0);
1592 Location right = locations->InAt(1);
1593 Register out = locations->Out().AsRegister<Register>();
1594 Label true_label, false_label;
1595
1596 switch (cond->InputAt(0)->GetType()) {
1597 default: {
1598 // Integer case.
1599 if (right.IsRegister()) {
1600 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1601 } else {
1602 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001603 __ CmpConstant(left.AsRegister<Register>(),
1604 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001605 }
Aart Bike9f37602015-10-09 11:15:55 -07001606 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001607 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001608 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001609 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001610 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001611 return;
1612 }
1613 case Primitive::kPrimLong:
1614 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1615 break;
1616 case Primitive::kPrimFloat:
1617 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1618 GenerateFPJumps(cond, &true_label, &false_label);
1619 break;
1620 case Primitive::kPrimDouble:
1621 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1622 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1623 GenerateFPJumps(cond, &true_label, &false_label);
1624 break;
1625 }
1626
1627 // Convert the jumps into the result.
1628 Label done_label;
1629
1630 // False case: result = 0.
1631 __ Bind(&false_label);
1632 __ LoadImmediate(out, 0);
1633 __ b(&done_label);
1634
1635 // True case: result = 1.
1636 __ Bind(&true_label);
1637 __ LoadImmediate(out, 1);
1638 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001639}
1640
1641void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001642 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001643}
1644
1645void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001646 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001647}
1648
1649void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001650 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001651}
1652
1653void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001654 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001655}
1656
1657void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001658 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001659}
1660
1661void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001662 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001663}
1664
1665void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001666 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001667}
1668
1669void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001670 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001671}
1672
1673void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001674 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001675}
1676
1677void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001678 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001679}
1680
1681void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001682 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001683}
1684
1685void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001686 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001687}
1688
Aart Bike9f37602015-10-09 11:15:55 -07001689void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001690 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001691}
1692
1693void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001694 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001695}
1696
1697void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001698 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001699}
1700
1701void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001702 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001703}
1704
1705void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001706 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001707}
1708
1709void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001710 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001711}
1712
1713void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001714 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001715}
1716
1717void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001718 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001719}
1720
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001721void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001722 LocationSummary* locations =
1723 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001724 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001725}
1726
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001727void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001728 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001729}
1730
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001731void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1732 LocationSummary* locations =
1733 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1734 locations->SetOut(Location::ConstantLocation(constant));
1735}
1736
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001737void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001738 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001739}
1740
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001741void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001742 LocationSummary* locations =
1743 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001744 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001745}
1746
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001747void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001748 // Will be generated at use site.
1749}
1750
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001751void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1752 LocationSummary* locations =
1753 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1754 locations->SetOut(Location::ConstantLocation(constant));
1755}
1756
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001757void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001758 // Will be generated at use site.
1759}
1760
1761void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1762 LocationSummary* locations =
1763 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1764 locations->SetOut(Location::ConstantLocation(constant));
1765}
1766
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001767void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001768 // Will be generated at use site.
1769}
1770
Calin Juravle27df7582015-04-17 19:12:31 +01001771void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1772 memory_barrier->SetLocations(nullptr);
1773}
1774
1775void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00001776 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01001777}
1778
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001779void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001780 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001781}
1782
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001783void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001784 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001785}
1786
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001787void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001788 LocationSummary* locations =
1789 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001790 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001791}
1792
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001793void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001794 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001795}
1796
Calin Juravle175dc732015-08-25 15:42:32 +01001797void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1798 // The trampoline uses the same calling convention as dex calling conventions,
1799 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1800 // the method_idx.
1801 HandleInvoke(invoke);
1802}
1803
1804void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1805 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1806}
1807
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001808void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001809 // Explicit clinit checks triggered by static invokes must have been pruned by
1810 // art::PrepareForRegisterAllocation.
1811 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001812
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001813 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001814 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001815 codegen_->GetInstructionSetFeatures());
1816 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001817 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1818 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1819 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001820 return;
1821 }
1822
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001823 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001824
1825 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1826 if (invoke->HasPcRelativeDexCache()) {
1827 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1828 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001829}
1830
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001831static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1832 if (invoke->GetLocations()->Intrinsified()) {
1833 IntrinsicCodeGeneratorARM intrinsic(codegen);
1834 intrinsic.Dispatch(invoke);
1835 return true;
1836 }
1837 return false;
1838}
1839
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001840void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001841 // Explicit clinit checks triggered by static invokes must have been pruned by
1842 // art::PrepareForRegisterAllocation.
1843 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001844
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001845 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1846 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001847 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001848
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001849 LocationSummary* locations = invoke->GetLocations();
1850 codegen_->GenerateStaticOrDirectCall(
1851 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001852 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001853}
1854
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001855void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001856 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001857 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001858}
1859
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001860void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001861 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001862 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001863 codegen_->GetInstructionSetFeatures());
1864 if (intrinsic.TryDispatch(invoke)) {
1865 return;
1866 }
1867
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001868 HandleInvoke(invoke);
1869}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001870
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001871void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001872 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1873 return;
1874 }
1875
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001876 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001877 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001878 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001879}
1880
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001881void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1882 HandleInvoke(invoke);
1883 // Add the hidden argument.
1884 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1885}
1886
1887void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1888 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001889 LocationSummary* locations = invoke->GetLocations();
1890 Register temp = locations->GetTemp(0).AsRegister<Register>();
1891 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray88f288e2016-06-29 08:17:52 +00001892 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1893 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001894 Location receiver = locations->InAt(0);
1895 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1896
Roland Levillain3b359c72015-11-17 19:35:12 +00001897 // Set the hidden argument. This is safe to do this here, as R12
1898 // won't be modified thereafter, before the `blx` (call) instruction.
1899 DCHECK_EQ(R12, hidden_reg);
1900 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001901
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001902 if (receiver.IsStackSlot()) {
1903 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00001904 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001905 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1906 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00001907 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00001908 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001909 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001910 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00001911 // Instead of simply (possibly) unpoisoning `temp` here, we should
1912 // emit a read barrier for the previous class reference load.
1913 // However this is not required in practice, as this is an
1914 // intermediate/temporary reference and because the current
1915 // concurrent copying collector keeps the from-space memory
1916 // intact/accessible until the end of the marking phase (the
1917 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01001918 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001919 // temp = temp->GetImtEntryAt(method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001920 uint32_t entry_point =
1921 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray88f288e2016-06-29 08:17:52 +00001922 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001923 // LR = temp->GetEntryPoint();
1924 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1925 // LR();
1926 __ blx(LR);
1927 DCHECK(!codegen_->IsLeafMethod());
1928 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1929}
1930
Roland Levillain88cb1752014-10-20 16:36:47 +01001931void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1932 LocationSummary* locations =
1933 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1934 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001935 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001936 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001937 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1938 break;
1939 }
1940 case Primitive::kPrimLong: {
1941 locations->SetInAt(0, Location::RequiresRegister());
1942 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001943 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001944 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001945
Roland Levillain88cb1752014-10-20 16:36:47 +01001946 case Primitive::kPrimFloat:
1947 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001948 locations->SetInAt(0, Location::RequiresFpuRegister());
1949 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001950 break;
1951
1952 default:
1953 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1954 }
1955}
1956
1957void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1958 LocationSummary* locations = neg->GetLocations();
1959 Location out = locations->Out();
1960 Location in = locations->InAt(0);
1961 switch (neg->GetResultType()) {
1962 case Primitive::kPrimInt:
1963 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001964 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001965 break;
1966
1967 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001968 DCHECK(in.IsRegisterPair());
1969 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1970 __ rsbs(out.AsRegisterPairLow<Register>(),
1971 in.AsRegisterPairLow<Register>(),
1972 ShifterOperand(0));
1973 // We cannot emit an RSC (Reverse Subtract with Carry)
1974 // instruction here, as it does not exist in the Thumb-2
1975 // instruction set. We use the following approach
1976 // using SBC and SUB instead.
1977 //
1978 // out.hi = -C
1979 __ sbc(out.AsRegisterPairHigh<Register>(),
1980 out.AsRegisterPairHigh<Register>(),
1981 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1982 // out.hi = out.hi - in.hi
1983 __ sub(out.AsRegisterPairHigh<Register>(),
1984 out.AsRegisterPairHigh<Register>(),
1985 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1986 break;
1987
Roland Levillain88cb1752014-10-20 16:36:47 +01001988 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001989 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001990 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001991 break;
1992
Roland Levillain88cb1752014-10-20 16:36:47 +01001993 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001994 DCHECK(in.IsFpuRegisterPair());
1995 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1996 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001997 break;
1998
1999 default:
2000 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2001 }
2002}
2003
Roland Levillaindff1f282014-11-05 14:15:05 +00002004void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002005 Primitive::Type result_type = conversion->GetResultType();
2006 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002007 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002008
Roland Levillain5b3ee562015-04-14 16:02:41 +01002009 // The float-to-long, double-to-long and long-to-float type conversions
2010 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002011 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002012 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2013 && result_type == Primitive::kPrimLong)
2014 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002015 ? LocationSummary::kCall
2016 : LocationSummary::kNoCall;
2017 LocationSummary* locations =
2018 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2019
David Brazdilb2bd1c52015-03-25 11:17:37 +00002020 // The Java language does not allow treating boolean as an integral type but
2021 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002022
Roland Levillaindff1f282014-11-05 14:15:05 +00002023 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002024 case Primitive::kPrimByte:
2025 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002026 case Primitive::kPrimLong:
2027 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002028 case Primitive::kPrimBoolean:
2029 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002030 case Primitive::kPrimShort:
2031 case Primitive::kPrimInt:
2032 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002033 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002034 locations->SetInAt(0, Location::RequiresRegister());
2035 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2036 break;
2037
2038 default:
2039 LOG(FATAL) << "Unexpected type conversion from " << input_type
2040 << " to " << result_type;
2041 }
2042 break;
2043
Roland Levillain01a8d712014-11-14 16:27:39 +00002044 case Primitive::kPrimShort:
2045 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002046 case Primitive::kPrimLong:
2047 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002048 case Primitive::kPrimBoolean:
2049 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002050 case Primitive::kPrimByte:
2051 case Primitive::kPrimInt:
2052 case Primitive::kPrimChar:
2053 // Processing a Dex `int-to-short' instruction.
2054 locations->SetInAt(0, Location::RequiresRegister());
2055 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2056 break;
2057
2058 default:
2059 LOG(FATAL) << "Unexpected type conversion from " << input_type
2060 << " to " << result_type;
2061 }
2062 break;
2063
Roland Levillain946e1432014-11-11 17:35:19 +00002064 case Primitive::kPrimInt:
2065 switch (input_type) {
2066 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002067 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002068 locations->SetInAt(0, Location::Any());
2069 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2070 break;
2071
2072 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002073 // Processing a Dex `float-to-int' instruction.
2074 locations->SetInAt(0, Location::RequiresFpuRegister());
2075 locations->SetOut(Location::RequiresRegister());
2076 locations->AddTemp(Location::RequiresFpuRegister());
2077 break;
2078
Roland Levillain946e1432014-11-11 17:35:19 +00002079 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002080 // Processing a Dex `double-to-int' instruction.
2081 locations->SetInAt(0, Location::RequiresFpuRegister());
2082 locations->SetOut(Location::RequiresRegister());
2083 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002084 break;
2085
2086 default:
2087 LOG(FATAL) << "Unexpected type conversion from " << input_type
2088 << " to " << result_type;
2089 }
2090 break;
2091
Roland Levillaindff1f282014-11-05 14:15:05 +00002092 case Primitive::kPrimLong:
2093 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002094 case Primitive::kPrimBoolean:
2095 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002096 case Primitive::kPrimByte:
2097 case Primitive::kPrimShort:
2098 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002099 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002100 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002101 locations->SetInAt(0, Location::RequiresRegister());
2102 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2103 break;
2104
Roland Levillain624279f2014-12-04 11:54:28 +00002105 case Primitive::kPrimFloat: {
2106 // Processing a Dex `float-to-long' instruction.
2107 InvokeRuntimeCallingConvention calling_convention;
2108 locations->SetInAt(0, Location::FpuRegisterLocation(
2109 calling_convention.GetFpuRegisterAt(0)));
2110 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2111 break;
2112 }
2113
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002114 case Primitive::kPrimDouble: {
2115 // Processing a Dex `double-to-long' instruction.
2116 InvokeRuntimeCallingConvention calling_convention;
2117 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2118 calling_convention.GetFpuRegisterAt(0),
2119 calling_convention.GetFpuRegisterAt(1)));
2120 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002121 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002122 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002123
2124 default:
2125 LOG(FATAL) << "Unexpected type conversion from " << input_type
2126 << " to " << result_type;
2127 }
2128 break;
2129
Roland Levillain981e4542014-11-14 11:47:14 +00002130 case Primitive::kPrimChar:
2131 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002132 case Primitive::kPrimLong:
2133 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002134 case Primitive::kPrimBoolean:
2135 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002136 case Primitive::kPrimByte:
2137 case Primitive::kPrimShort:
2138 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002139 // Processing a Dex `int-to-char' instruction.
2140 locations->SetInAt(0, Location::RequiresRegister());
2141 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2142 break;
2143
2144 default:
2145 LOG(FATAL) << "Unexpected type conversion from " << input_type
2146 << " to " << result_type;
2147 }
2148 break;
2149
Roland Levillaindff1f282014-11-05 14:15:05 +00002150 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002151 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002152 case Primitive::kPrimBoolean:
2153 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002154 case Primitive::kPrimByte:
2155 case Primitive::kPrimShort:
2156 case Primitive::kPrimInt:
2157 case Primitive::kPrimChar:
2158 // Processing a Dex `int-to-float' instruction.
2159 locations->SetInAt(0, Location::RequiresRegister());
2160 locations->SetOut(Location::RequiresFpuRegister());
2161 break;
2162
Roland Levillain5b3ee562015-04-14 16:02:41 +01002163 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002164 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002165 InvokeRuntimeCallingConvention calling_convention;
2166 locations->SetInAt(0, Location::RegisterPairLocation(
2167 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2168 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002169 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002170 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002171
Roland Levillaincff13742014-11-17 14:32:17 +00002172 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002173 // Processing a Dex `double-to-float' instruction.
2174 locations->SetInAt(0, Location::RequiresFpuRegister());
2175 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002176 break;
2177
2178 default:
2179 LOG(FATAL) << "Unexpected type conversion from " << input_type
2180 << " to " << result_type;
2181 };
2182 break;
2183
Roland Levillaindff1f282014-11-05 14:15:05 +00002184 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002185 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002186 case Primitive::kPrimBoolean:
2187 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002188 case Primitive::kPrimByte:
2189 case Primitive::kPrimShort:
2190 case Primitive::kPrimInt:
2191 case Primitive::kPrimChar:
2192 // Processing a Dex `int-to-double' instruction.
2193 locations->SetInAt(0, Location::RequiresRegister());
2194 locations->SetOut(Location::RequiresFpuRegister());
2195 break;
2196
2197 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002198 // Processing a Dex `long-to-double' instruction.
2199 locations->SetInAt(0, Location::RequiresRegister());
2200 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002201 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002202 locations->AddTemp(Location::RequiresFpuRegister());
2203 break;
2204
Roland Levillaincff13742014-11-17 14:32:17 +00002205 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002206 // Processing a Dex `float-to-double' instruction.
2207 locations->SetInAt(0, Location::RequiresFpuRegister());
2208 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002209 break;
2210
2211 default:
2212 LOG(FATAL) << "Unexpected type conversion from " << input_type
2213 << " to " << result_type;
2214 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002215 break;
2216
2217 default:
2218 LOG(FATAL) << "Unexpected type conversion from " << input_type
2219 << " to " << result_type;
2220 }
2221}
2222
2223void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2224 LocationSummary* locations = conversion->GetLocations();
2225 Location out = locations->Out();
2226 Location in = locations->InAt(0);
2227 Primitive::Type result_type = conversion->GetResultType();
2228 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002229 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002230 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002231 case Primitive::kPrimByte:
2232 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002233 case Primitive::kPrimLong:
2234 // Type conversion from long to byte is a result of code transformations.
2235 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2236 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002237 case Primitive::kPrimBoolean:
2238 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002239 case Primitive::kPrimShort:
2240 case Primitive::kPrimInt:
2241 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002242 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002243 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002244 break;
2245
2246 default:
2247 LOG(FATAL) << "Unexpected type conversion from " << input_type
2248 << " to " << result_type;
2249 }
2250 break;
2251
Roland Levillain01a8d712014-11-14 16:27:39 +00002252 case Primitive::kPrimShort:
2253 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002254 case Primitive::kPrimLong:
2255 // Type conversion from long to short is a result of code transformations.
2256 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2257 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002258 case Primitive::kPrimBoolean:
2259 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002260 case Primitive::kPrimByte:
2261 case Primitive::kPrimInt:
2262 case Primitive::kPrimChar:
2263 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002264 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002265 break;
2266
2267 default:
2268 LOG(FATAL) << "Unexpected type conversion from " << input_type
2269 << " to " << result_type;
2270 }
2271 break;
2272
Roland Levillain946e1432014-11-11 17:35:19 +00002273 case Primitive::kPrimInt:
2274 switch (input_type) {
2275 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002276 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002277 DCHECK(out.IsRegister());
2278 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002279 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002280 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002281 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002282 } else {
2283 DCHECK(in.IsConstant());
2284 DCHECK(in.GetConstant()->IsLongConstant());
2285 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002286 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002287 }
2288 break;
2289
Roland Levillain3f8f9362014-12-02 17:45:01 +00002290 case Primitive::kPrimFloat: {
2291 // Processing a Dex `float-to-int' instruction.
2292 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002293 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002294 __ vmovrs(out.AsRegister<Register>(), temp);
2295 break;
2296 }
2297
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002298 case Primitive::kPrimDouble: {
2299 // Processing a Dex `double-to-int' instruction.
2300 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002301 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002302 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002303 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002304 }
Roland Levillain946e1432014-11-11 17:35:19 +00002305
2306 default:
2307 LOG(FATAL) << "Unexpected type conversion from " << input_type
2308 << " to " << result_type;
2309 }
2310 break;
2311
Roland Levillaindff1f282014-11-05 14:15:05 +00002312 case Primitive::kPrimLong:
2313 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002314 case Primitive::kPrimBoolean:
2315 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002316 case Primitive::kPrimByte:
2317 case Primitive::kPrimShort:
2318 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002319 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002320 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002321 DCHECK(out.IsRegisterPair());
2322 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002323 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002324 // Sign extension.
2325 __ Asr(out.AsRegisterPairHigh<Register>(),
2326 out.AsRegisterPairLow<Register>(),
2327 31);
2328 break;
2329
2330 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002331 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002332 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2333 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002334 conversion->GetDexPc(),
2335 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002336 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002337 break;
2338
Roland Levillaindff1f282014-11-05 14:15:05 +00002339 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002340 // Processing a Dex `double-to-long' instruction.
2341 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2342 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002343 conversion->GetDexPc(),
2344 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002345 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002346 break;
2347
2348 default:
2349 LOG(FATAL) << "Unexpected type conversion from " << input_type
2350 << " to " << result_type;
2351 }
2352 break;
2353
Roland Levillain981e4542014-11-14 11:47:14 +00002354 case Primitive::kPrimChar:
2355 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002356 case Primitive::kPrimLong:
2357 // Type conversion from long to char is a result of code transformations.
2358 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2359 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002360 case Primitive::kPrimBoolean:
2361 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002362 case Primitive::kPrimByte:
2363 case Primitive::kPrimShort:
2364 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002365 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002366 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002367 break;
2368
2369 default:
2370 LOG(FATAL) << "Unexpected type conversion from " << input_type
2371 << " to " << result_type;
2372 }
2373 break;
2374
Roland Levillaindff1f282014-11-05 14:15:05 +00002375 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002376 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002377 case Primitive::kPrimBoolean:
2378 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002379 case Primitive::kPrimByte:
2380 case Primitive::kPrimShort:
2381 case Primitive::kPrimInt:
2382 case Primitive::kPrimChar: {
2383 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002384 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2385 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002386 break;
2387 }
2388
Roland Levillain5b3ee562015-04-14 16:02:41 +01002389 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002390 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002391 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2392 conversion,
2393 conversion->GetDexPc(),
2394 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002395 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002396 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002397
Roland Levillaincff13742014-11-17 14:32:17 +00002398 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002399 // Processing a Dex `double-to-float' instruction.
2400 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2401 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002402 break;
2403
2404 default:
2405 LOG(FATAL) << "Unexpected type conversion from " << input_type
2406 << " to " << result_type;
2407 };
2408 break;
2409
Roland Levillaindff1f282014-11-05 14:15:05 +00002410 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002411 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002412 case Primitive::kPrimBoolean:
2413 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002414 case Primitive::kPrimByte:
2415 case Primitive::kPrimShort:
2416 case Primitive::kPrimInt:
2417 case Primitive::kPrimChar: {
2418 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002419 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002420 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2421 out.AsFpuRegisterPairLow<SRegister>());
2422 break;
2423 }
2424
Roland Levillain647b9ed2014-11-27 12:06:00 +00002425 case Primitive::kPrimLong: {
2426 // Processing a Dex `long-to-double' instruction.
2427 Register low = in.AsRegisterPairLow<Register>();
2428 Register high = in.AsRegisterPairHigh<Register>();
2429 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2430 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002431 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002432 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002433 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2434 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002435
Roland Levillain682393c2015-04-14 15:57:52 +01002436 // temp_d = int-to-double(high)
2437 __ vmovsr(temp_s, high);
2438 __ vcvtdi(temp_d, temp_s);
2439 // constant_d = k2Pow32EncodingForDouble
2440 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2441 // out_d = unsigned-to-double(low)
2442 __ vmovsr(out_s, low);
2443 __ vcvtdu(out_d, out_s);
2444 // out_d += temp_d * constant_d
2445 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002446 break;
2447 }
2448
Roland Levillaincff13742014-11-17 14:32:17 +00002449 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002450 // Processing a Dex `float-to-double' instruction.
2451 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2452 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002453 break;
2454
2455 default:
2456 LOG(FATAL) << "Unexpected type conversion from " << input_type
2457 << " to " << result_type;
2458 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002459 break;
2460
2461 default:
2462 LOG(FATAL) << "Unexpected type conversion from " << input_type
2463 << " to " << result_type;
2464 }
2465}
2466
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002467void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002468 LocationSummary* locations =
2469 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002470 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002471 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002472 locations->SetInAt(0, Location::RequiresRegister());
2473 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002474 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2475 break;
2476 }
2477
2478 case Primitive::kPrimLong: {
2479 locations->SetInAt(0, Location::RequiresRegister());
2480 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002481 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002482 break;
2483 }
2484
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002485 case Primitive::kPrimFloat:
2486 case Primitive::kPrimDouble: {
2487 locations->SetInAt(0, Location::RequiresFpuRegister());
2488 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002489 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002490 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002491 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002492
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002493 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002494 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002495 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002496}
2497
2498void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2499 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002500 Location out = locations->Out();
2501 Location first = locations->InAt(0);
2502 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002503 switch (add->GetResultType()) {
2504 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002505 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002506 __ add(out.AsRegister<Register>(),
2507 first.AsRegister<Register>(),
2508 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002509 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002510 __ AddConstant(out.AsRegister<Register>(),
2511 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002512 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002513 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002514 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002515
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002516 case Primitive::kPrimLong: {
2517 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002518 __ adds(out.AsRegisterPairLow<Register>(),
2519 first.AsRegisterPairLow<Register>(),
2520 ShifterOperand(second.AsRegisterPairLow<Register>()));
2521 __ adc(out.AsRegisterPairHigh<Register>(),
2522 first.AsRegisterPairHigh<Register>(),
2523 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002524 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002525 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002526
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002527 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002528 __ vadds(out.AsFpuRegister<SRegister>(),
2529 first.AsFpuRegister<SRegister>(),
2530 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002531 break;
2532
2533 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002534 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2535 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2536 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002537 break;
2538
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002539 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002540 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002541 }
2542}
2543
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002544void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002545 LocationSummary* locations =
2546 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002547 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002548 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002549 locations->SetInAt(0, Location::RequiresRegister());
2550 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002551 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2552 break;
2553 }
2554
2555 case Primitive::kPrimLong: {
2556 locations->SetInAt(0, Location::RequiresRegister());
2557 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002558 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002559 break;
2560 }
Calin Juravle11351682014-10-23 15:38:15 +01002561 case Primitive::kPrimFloat:
2562 case Primitive::kPrimDouble: {
2563 locations->SetInAt(0, Location::RequiresFpuRegister());
2564 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002565 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002566 break;
Calin Juravle11351682014-10-23 15:38:15 +01002567 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002568 default:
Calin Juravle11351682014-10-23 15:38:15 +01002569 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002570 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002571}
2572
2573void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2574 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002575 Location out = locations->Out();
2576 Location first = locations->InAt(0);
2577 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002578 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002579 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002580 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002581 __ sub(out.AsRegister<Register>(),
2582 first.AsRegister<Register>(),
2583 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002584 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002585 __ AddConstant(out.AsRegister<Register>(),
2586 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002587 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002588 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002589 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002590 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002591
Calin Juravle11351682014-10-23 15:38:15 +01002592 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002593 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002594 __ subs(out.AsRegisterPairLow<Register>(),
2595 first.AsRegisterPairLow<Register>(),
2596 ShifterOperand(second.AsRegisterPairLow<Register>()));
2597 __ sbc(out.AsRegisterPairHigh<Register>(),
2598 first.AsRegisterPairHigh<Register>(),
2599 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002600 break;
Calin Juravle11351682014-10-23 15:38:15 +01002601 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002602
Calin Juravle11351682014-10-23 15:38:15 +01002603 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002604 __ vsubs(out.AsFpuRegister<SRegister>(),
2605 first.AsFpuRegister<SRegister>(),
2606 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002607 break;
Calin Juravle11351682014-10-23 15:38:15 +01002608 }
2609
2610 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002611 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2612 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2613 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002614 break;
2615 }
2616
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002617
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002618 default:
Calin Juravle11351682014-10-23 15:38:15 +01002619 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002620 }
2621}
2622
Calin Juravle34bacdf2014-10-07 20:23:36 +01002623void LocationsBuilderARM::VisitMul(HMul* mul) {
2624 LocationSummary* locations =
2625 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2626 switch (mul->GetResultType()) {
2627 case Primitive::kPrimInt:
2628 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002629 locations->SetInAt(0, Location::RequiresRegister());
2630 locations->SetInAt(1, Location::RequiresRegister());
2631 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002632 break;
2633 }
2634
Calin Juravleb5bfa962014-10-21 18:02:24 +01002635 case Primitive::kPrimFloat:
2636 case Primitive::kPrimDouble: {
2637 locations->SetInAt(0, Location::RequiresFpuRegister());
2638 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002639 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002640 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002641 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002642
2643 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002644 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002645 }
2646}
2647
2648void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2649 LocationSummary* locations = mul->GetLocations();
2650 Location out = locations->Out();
2651 Location first = locations->InAt(0);
2652 Location second = locations->InAt(1);
2653 switch (mul->GetResultType()) {
2654 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002655 __ mul(out.AsRegister<Register>(),
2656 first.AsRegister<Register>(),
2657 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002658 break;
2659 }
2660 case Primitive::kPrimLong: {
2661 Register out_hi = out.AsRegisterPairHigh<Register>();
2662 Register out_lo = out.AsRegisterPairLow<Register>();
2663 Register in1_hi = first.AsRegisterPairHigh<Register>();
2664 Register in1_lo = first.AsRegisterPairLow<Register>();
2665 Register in2_hi = second.AsRegisterPairHigh<Register>();
2666 Register in2_lo = second.AsRegisterPairLow<Register>();
2667
2668 // Extra checks to protect caused by the existence of R1_R2.
2669 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2670 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2671 DCHECK_NE(out_hi, in1_lo);
2672 DCHECK_NE(out_hi, in2_lo);
2673
2674 // input: in1 - 64 bits, in2 - 64 bits
2675 // output: out
2676 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2677 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2678 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2679
2680 // IP <- in1.lo * in2.hi
2681 __ mul(IP, in1_lo, in2_hi);
2682 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2683 __ mla(out_hi, in1_hi, in2_lo, IP);
2684 // out.lo <- (in1.lo * in2.lo)[31:0];
2685 __ umull(out_lo, IP, in1_lo, in2_lo);
2686 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2687 __ add(out_hi, out_hi, ShifterOperand(IP));
2688 break;
2689 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002690
2691 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002692 __ vmuls(out.AsFpuRegister<SRegister>(),
2693 first.AsFpuRegister<SRegister>(),
2694 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002695 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002696 }
2697
2698 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002699 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2700 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2701 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002702 break;
2703 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002704
2705 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002706 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002707 }
2708}
2709
Zheng Xuc6667102015-05-15 16:08:45 +08002710void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2711 DCHECK(instruction->IsDiv() || instruction->IsRem());
2712 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2713
2714 LocationSummary* locations = instruction->GetLocations();
2715 Location second = locations->InAt(1);
2716 DCHECK(second.IsConstant());
2717
2718 Register out = locations->Out().AsRegister<Register>();
2719 Register dividend = locations->InAt(0).AsRegister<Register>();
2720 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2721 DCHECK(imm == 1 || imm == -1);
2722
2723 if (instruction->IsRem()) {
2724 __ LoadImmediate(out, 0);
2725 } else {
2726 if (imm == 1) {
2727 __ Mov(out, dividend);
2728 } else {
2729 __ rsb(out, dividend, ShifterOperand(0));
2730 }
2731 }
2732}
2733
2734void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2735 DCHECK(instruction->IsDiv() || instruction->IsRem());
2736 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2737
2738 LocationSummary* locations = instruction->GetLocations();
2739 Location second = locations->InAt(1);
2740 DCHECK(second.IsConstant());
2741
2742 Register out = locations->Out().AsRegister<Register>();
2743 Register dividend = locations->InAt(0).AsRegister<Register>();
2744 Register temp = locations->GetTemp(0).AsRegister<Register>();
2745 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002746 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002747 int ctz_imm = CTZ(abs_imm);
2748
2749 if (ctz_imm == 1) {
2750 __ Lsr(temp, dividend, 32 - ctz_imm);
2751 } else {
2752 __ Asr(temp, dividend, 31);
2753 __ Lsr(temp, temp, 32 - ctz_imm);
2754 }
2755 __ add(out, temp, ShifterOperand(dividend));
2756
2757 if (instruction->IsDiv()) {
2758 __ Asr(out, out, ctz_imm);
2759 if (imm < 0) {
2760 __ rsb(out, out, ShifterOperand(0));
2761 }
2762 } else {
2763 __ ubfx(out, out, 0, ctz_imm);
2764 __ sub(out, out, ShifterOperand(temp));
2765 }
2766}
2767
2768void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2769 DCHECK(instruction->IsDiv() || instruction->IsRem());
2770 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2771
2772 LocationSummary* locations = instruction->GetLocations();
2773 Location second = locations->InAt(1);
2774 DCHECK(second.IsConstant());
2775
2776 Register out = locations->Out().AsRegister<Register>();
2777 Register dividend = locations->InAt(0).AsRegister<Register>();
2778 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2779 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2780 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2781
2782 int64_t magic;
2783 int shift;
2784 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2785
2786 __ LoadImmediate(temp1, magic);
2787 __ smull(temp2, temp1, dividend, temp1);
2788
2789 if (imm > 0 && magic < 0) {
2790 __ add(temp1, temp1, ShifterOperand(dividend));
2791 } else if (imm < 0 && magic > 0) {
2792 __ sub(temp1, temp1, ShifterOperand(dividend));
2793 }
2794
2795 if (shift != 0) {
2796 __ Asr(temp1, temp1, shift);
2797 }
2798
2799 if (instruction->IsDiv()) {
2800 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2801 } else {
2802 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2803 // TODO: Strength reduction for mls.
2804 __ LoadImmediate(temp2, imm);
2805 __ mls(out, temp1, temp2, dividend);
2806 }
2807}
2808
2809void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2810 DCHECK(instruction->IsDiv() || instruction->IsRem());
2811 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2812
2813 LocationSummary* locations = instruction->GetLocations();
2814 Location second = locations->InAt(1);
2815 DCHECK(second.IsConstant());
2816
2817 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2818 if (imm == 0) {
2819 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2820 } else if (imm == 1 || imm == -1) {
2821 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002822 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002823 DivRemByPowerOfTwo(instruction);
2824 } else {
2825 DCHECK(imm <= -2 || imm >= 2);
2826 GenerateDivRemWithAnyConstant(instruction);
2827 }
2828}
2829
Calin Juravle7c4954d2014-10-28 16:57:40 +00002830void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002831 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2832 if (div->GetResultType() == Primitive::kPrimLong) {
2833 // pLdiv runtime call.
2834 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002835 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2836 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002837 } else if (div->GetResultType() == Primitive::kPrimInt &&
2838 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2839 // pIdivmod runtime call.
2840 call_kind = LocationSummary::kCall;
2841 }
2842
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002843 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2844
Calin Juravle7c4954d2014-10-28 16:57:40 +00002845 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002846 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002847 if (div->InputAt(1)->IsConstant()) {
2848 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002849 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002850 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002851 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
2852 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002853 // No temp register required.
2854 } else {
2855 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002856 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002857 locations->AddTemp(Location::RequiresRegister());
2858 }
2859 }
2860 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002861 locations->SetInAt(0, Location::RequiresRegister());
2862 locations->SetInAt(1, Location::RequiresRegister());
2863 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2864 } else {
2865 InvokeRuntimeCallingConvention calling_convention;
2866 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2867 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2868 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2869 // we only need the former.
2870 locations->SetOut(Location::RegisterLocation(R0));
2871 }
Calin Juravled0d48522014-11-04 16:40:20 +00002872 break;
2873 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002874 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002875 InvokeRuntimeCallingConvention calling_convention;
2876 locations->SetInAt(0, Location::RegisterPairLocation(
2877 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2878 locations->SetInAt(1, Location::RegisterPairLocation(
2879 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002880 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002881 break;
2882 }
2883 case Primitive::kPrimFloat:
2884 case Primitive::kPrimDouble: {
2885 locations->SetInAt(0, Location::RequiresFpuRegister());
2886 locations->SetInAt(1, Location::RequiresFpuRegister());
2887 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2888 break;
2889 }
2890
2891 default:
2892 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2893 }
2894}
2895
2896void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2897 LocationSummary* locations = div->GetLocations();
2898 Location out = locations->Out();
2899 Location first = locations->InAt(0);
2900 Location second = locations->InAt(1);
2901
2902 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002903 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002904 if (second.IsConstant()) {
2905 GenerateDivRemConstantIntegral(div);
2906 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002907 __ sdiv(out.AsRegister<Register>(),
2908 first.AsRegister<Register>(),
2909 second.AsRegister<Register>());
2910 } else {
2911 InvokeRuntimeCallingConvention calling_convention;
2912 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2913 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2914 DCHECK_EQ(R0, out.AsRegister<Register>());
2915
2916 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002917 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002918 }
Calin Juravled0d48522014-11-04 16:40:20 +00002919 break;
2920 }
2921
Calin Juravle7c4954d2014-10-28 16:57:40 +00002922 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002923 InvokeRuntimeCallingConvention calling_convention;
2924 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2925 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2926 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2927 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2928 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002929 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002930
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002931 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002932 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002933 break;
2934 }
2935
2936 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002937 __ vdivs(out.AsFpuRegister<SRegister>(),
2938 first.AsFpuRegister<SRegister>(),
2939 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002940 break;
2941 }
2942
2943 case Primitive::kPrimDouble: {
2944 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2945 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2946 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2947 break;
2948 }
2949
2950 default:
2951 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2952 }
2953}
2954
Calin Juravlebacfec32014-11-14 15:54:36 +00002955void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002956 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002957
2958 // Most remainders are implemented in the runtime.
2959 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002960 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2961 // sdiv will be replaced by other instruction sequence.
2962 call_kind = LocationSummary::kNoCall;
2963 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2964 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002965 // Have hardware divide instruction for int, do it with three instructions.
2966 call_kind = LocationSummary::kNoCall;
2967 }
2968
Calin Juravlebacfec32014-11-14 15:54:36 +00002969 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2970
Calin Juravled2ec87d2014-12-08 14:24:46 +00002971 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002972 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002973 if (rem->InputAt(1)->IsConstant()) {
2974 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002975 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002976 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002977 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
2978 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002979 // No temp register required.
2980 } else {
2981 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002982 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002983 locations->AddTemp(Location::RequiresRegister());
2984 }
2985 }
2986 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002987 locations->SetInAt(0, Location::RequiresRegister());
2988 locations->SetInAt(1, Location::RequiresRegister());
2989 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2990 locations->AddTemp(Location::RequiresRegister());
2991 } else {
2992 InvokeRuntimeCallingConvention calling_convention;
2993 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2994 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2995 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2996 // we only need the latter.
2997 locations->SetOut(Location::RegisterLocation(R1));
2998 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002999 break;
3000 }
3001 case Primitive::kPrimLong: {
3002 InvokeRuntimeCallingConvention calling_convention;
3003 locations->SetInAt(0, Location::RegisterPairLocation(
3004 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3005 locations->SetInAt(1, Location::RegisterPairLocation(
3006 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3007 // The runtime helper puts the output in R2,R3.
3008 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3009 break;
3010 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003011 case Primitive::kPrimFloat: {
3012 InvokeRuntimeCallingConvention calling_convention;
3013 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3014 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3015 locations->SetOut(Location::FpuRegisterLocation(S0));
3016 break;
3017 }
3018
Calin Juravlebacfec32014-11-14 15:54:36 +00003019 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003020 InvokeRuntimeCallingConvention calling_convention;
3021 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3022 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3023 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3024 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3025 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003026 break;
3027 }
3028
3029 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003030 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003031 }
3032}
3033
3034void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3035 LocationSummary* locations = rem->GetLocations();
3036 Location out = locations->Out();
3037 Location first = locations->InAt(0);
3038 Location second = locations->InAt(1);
3039
Calin Juravled2ec87d2014-12-08 14:24:46 +00003040 Primitive::Type type = rem->GetResultType();
3041 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003042 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003043 if (second.IsConstant()) {
3044 GenerateDivRemConstantIntegral(rem);
3045 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003046 Register reg1 = first.AsRegister<Register>();
3047 Register reg2 = second.AsRegister<Register>();
3048 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003049
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003050 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003051 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003052 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003053 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003054 } else {
3055 InvokeRuntimeCallingConvention calling_convention;
3056 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3057 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3058 DCHECK_EQ(R1, out.AsRegister<Register>());
3059
3060 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003061 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003062 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003063 break;
3064 }
3065
3066 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003067 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003068 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003069 break;
3070 }
3071
Calin Juravled2ec87d2014-12-08 14:24:46 +00003072 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003073 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003074 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003075 break;
3076 }
3077
Calin Juravlebacfec32014-11-14 15:54:36 +00003078 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003079 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003080 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003081 break;
3082 }
3083
3084 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003085 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003086 }
3087}
3088
Calin Juravled0d48522014-11-04 16:40:20 +00003089void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003090 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3091 ? LocationSummary::kCallOnSlowPath
3092 : LocationSummary::kNoCall;
3093 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003094 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003095 if (instruction->HasUses()) {
3096 locations->SetOut(Location::SameAsFirstInput());
3097 }
3098}
3099
3100void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003101 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003102 codegen_->AddSlowPath(slow_path);
3103
3104 LocationSummary* locations = instruction->GetLocations();
3105 Location value = locations->InAt(0);
3106
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003107 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003108 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003109 case Primitive::kPrimByte:
3110 case Primitive::kPrimChar:
3111 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003112 case Primitive::kPrimInt: {
3113 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003114 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003115 } else {
3116 DCHECK(value.IsConstant()) << value;
3117 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3118 __ b(slow_path->GetEntryLabel());
3119 }
3120 }
3121 break;
3122 }
3123 case Primitive::kPrimLong: {
3124 if (value.IsRegisterPair()) {
3125 __ orrs(IP,
3126 value.AsRegisterPairLow<Register>(),
3127 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3128 __ b(slow_path->GetEntryLabel(), EQ);
3129 } else {
3130 DCHECK(value.IsConstant()) << value;
3131 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3132 __ b(slow_path->GetEntryLabel());
3133 }
3134 }
3135 break;
3136 default:
3137 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3138 }
3139 }
Calin Juravled0d48522014-11-04 16:40:20 +00003140}
3141
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003142void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3143 Register in = locations->InAt(0).AsRegister<Register>();
3144 Location rhs = locations->InAt(1);
3145 Register out = locations->Out().AsRegister<Register>();
3146
3147 if (rhs.IsConstant()) {
3148 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3149 // so map all rotations to a +ve. equivalent in that range.
3150 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3151 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3152 if (rot) {
3153 // Rotate, mapping left rotations to right equivalents if necessary.
3154 // (e.g. left by 2 bits == right by 30.)
3155 __ Ror(out, in, rot);
3156 } else if (out != in) {
3157 __ Mov(out, in);
3158 }
3159 } else {
3160 __ Ror(out, in, rhs.AsRegister<Register>());
3161 }
3162}
3163
3164// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3165// rotates by swapping input regs (effectively rotating by the first 32-bits of
3166// a larger rotation) or flipping direction (thus treating larger right/left
3167// rotations as sub-word sized rotations in the other direction) as appropriate.
3168void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3169 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3170 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3171 Location rhs = locations->InAt(1);
3172 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3173 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3174
3175 if (rhs.IsConstant()) {
3176 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3177 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003178 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003179 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3180 // logic below to a simple pair of binary orr.
3181 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3182 if (rot >= kArmBitsPerWord) {
3183 rot -= kArmBitsPerWord;
3184 std::swap(in_reg_hi, in_reg_lo);
3185 }
3186 // Rotate, or mov to out for zero or word size rotations.
3187 if (rot != 0u) {
3188 __ Lsr(out_reg_hi, in_reg_hi, rot);
3189 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3190 __ Lsr(out_reg_lo, in_reg_lo, rot);
3191 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3192 } else {
3193 __ Mov(out_reg_lo, in_reg_lo);
3194 __ Mov(out_reg_hi, in_reg_hi);
3195 }
3196 } else {
3197 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3198 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3199 Label end;
3200 Label shift_by_32_plus_shift_right;
3201
3202 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3203 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3204 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3205 __ b(&shift_by_32_plus_shift_right, CC);
3206
3207 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3208 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3209 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3210 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3211 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3212 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3213 __ Lsr(shift_left, in_reg_hi, shift_right);
3214 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3215 __ b(&end);
3216
3217 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3218 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3219 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3220 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3221 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3222 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3223 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3224 __ Lsl(shift_right, in_reg_hi, shift_left);
3225 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3226
3227 __ Bind(&end);
3228 }
3229}
Roland Levillain22c49222016-03-18 14:04:28 +00003230
3231void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003232 LocationSummary* locations =
3233 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3234 switch (ror->GetResultType()) {
3235 case Primitive::kPrimInt: {
3236 locations->SetInAt(0, Location::RequiresRegister());
3237 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3238 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3239 break;
3240 }
3241 case Primitive::kPrimLong: {
3242 locations->SetInAt(0, Location::RequiresRegister());
3243 if (ror->InputAt(1)->IsConstant()) {
3244 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3245 } else {
3246 locations->SetInAt(1, Location::RequiresRegister());
3247 locations->AddTemp(Location::RequiresRegister());
3248 locations->AddTemp(Location::RequiresRegister());
3249 }
3250 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3251 break;
3252 }
3253 default:
3254 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3255 }
3256}
3257
Roland Levillain22c49222016-03-18 14:04:28 +00003258void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003259 LocationSummary* locations = ror->GetLocations();
3260 Primitive::Type type = ror->GetResultType();
3261 switch (type) {
3262 case Primitive::kPrimInt: {
3263 HandleIntegerRotate(locations);
3264 break;
3265 }
3266 case Primitive::kPrimLong: {
3267 HandleLongRotate(locations);
3268 break;
3269 }
3270 default:
3271 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003272 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003273 }
3274}
3275
Calin Juravle9aec02f2014-11-18 23:06:35 +00003276void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3277 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3278
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003279 LocationSummary* locations =
3280 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003281
3282 switch (op->GetResultType()) {
3283 case Primitive::kPrimInt: {
3284 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003285 if (op->InputAt(1)->IsConstant()) {
3286 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3287 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3288 } else {
3289 locations->SetInAt(1, Location::RequiresRegister());
3290 // Make the output overlap, as it will be used to hold the masked
3291 // second input.
3292 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3293 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003294 break;
3295 }
3296 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003297 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003298 if (op->InputAt(1)->IsConstant()) {
3299 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3300 // For simplicity, use kOutputOverlap even though we only require that low registers
3301 // don't clash with high registers which the register allocator currently guarantees.
3302 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3303 } else {
3304 locations->SetInAt(1, Location::RequiresRegister());
3305 locations->AddTemp(Location::RequiresRegister());
3306 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3307 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003308 break;
3309 }
3310 default:
3311 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3312 }
3313}
3314
3315void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3316 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3317
3318 LocationSummary* locations = op->GetLocations();
3319 Location out = locations->Out();
3320 Location first = locations->InAt(0);
3321 Location second = locations->InAt(1);
3322
3323 Primitive::Type type = op->GetResultType();
3324 switch (type) {
3325 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003326 Register out_reg = out.AsRegister<Register>();
3327 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003328 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003329 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003330 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003331 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003332 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003333 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003334 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003335 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003336 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003337 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003338 }
3339 } else {
3340 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003341 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003342 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003343 __ Mov(out_reg, first_reg);
3344 } else if (op->IsShl()) {
3345 __ Lsl(out_reg, first_reg, shift_value);
3346 } else if (op->IsShr()) {
3347 __ Asr(out_reg, first_reg, shift_value);
3348 } else {
3349 __ Lsr(out_reg, first_reg, shift_value);
3350 }
3351 }
3352 break;
3353 }
3354 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003355 Register o_h = out.AsRegisterPairHigh<Register>();
3356 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003357
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003358 Register high = first.AsRegisterPairHigh<Register>();
3359 Register low = first.AsRegisterPairLow<Register>();
3360
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003361 if (second.IsRegister()) {
3362 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003363
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003364 Register second_reg = second.AsRegister<Register>();
3365
3366 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003367 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003368 // Shift the high part
3369 __ Lsl(o_h, high, o_l);
3370 // Shift the low part and `or` what overflew on the high part
3371 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3372 __ Lsr(temp, low, temp);
3373 __ orr(o_h, o_h, ShifterOperand(temp));
3374 // If the shift is > 32 bits, override the high part
3375 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3376 __ it(PL);
3377 __ Lsl(o_h, low, temp, PL);
3378 // Shift the low part
3379 __ Lsl(o_l, low, o_l);
3380 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003381 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003382 // Shift the low part
3383 __ Lsr(o_l, low, o_h);
3384 // Shift the high part and `or` what underflew on the low part
3385 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3386 __ Lsl(temp, high, temp);
3387 __ orr(o_l, o_l, ShifterOperand(temp));
3388 // If the shift is > 32 bits, override the low part
3389 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3390 __ it(PL);
3391 __ Asr(o_l, high, temp, PL);
3392 // Shift the high part
3393 __ Asr(o_h, high, o_h);
3394 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003395 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003396 // same as Shr except we use `Lsr`s and not `Asr`s
3397 __ Lsr(o_l, low, o_h);
3398 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3399 __ Lsl(temp, high, temp);
3400 __ orr(o_l, o_l, ShifterOperand(temp));
3401 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3402 __ it(PL);
3403 __ Lsr(o_l, high, temp, PL);
3404 __ Lsr(o_h, high, o_h);
3405 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003406 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003407 // Register allocator doesn't create partial overlap.
3408 DCHECK_NE(o_l, high);
3409 DCHECK_NE(o_h, low);
3410 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003411 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003412 if (shift_value > 32) {
3413 if (op->IsShl()) {
3414 __ Lsl(o_h, low, shift_value - 32);
3415 __ LoadImmediate(o_l, 0);
3416 } else if (op->IsShr()) {
3417 __ Asr(o_l, high, shift_value - 32);
3418 __ Asr(o_h, high, 31);
3419 } else {
3420 __ Lsr(o_l, high, shift_value - 32);
3421 __ LoadImmediate(o_h, 0);
3422 }
3423 } else if (shift_value == 32) {
3424 if (op->IsShl()) {
3425 __ mov(o_h, ShifterOperand(low));
3426 __ LoadImmediate(o_l, 0);
3427 } else if (op->IsShr()) {
3428 __ mov(o_l, ShifterOperand(high));
3429 __ Asr(o_h, high, 31);
3430 } else {
3431 __ mov(o_l, ShifterOperand(high));
3432 __ LoadImmediate(o_h, 0);
3433 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003434 } else if (shift_value == 1) {
3435 if (op->IsShl()) {
3436 __ Lsls(o_l, low, 1);
3437 __ adc(o_h, high, ShifterOperand(high));
3438 } else if (op->IsShr()) {
3439 __ Asrs(o_h, high, 1);
3440 __ Rrx(o_l, low);
3441 } else {
3442 __ Lsrs(o_h, high, 1);
3443 __ Rrx(o_l, low);
3444 }
3445 } else {
3446 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003447 if (op->IsShl()) {
3448 __ Lsl(o_h, high, shift_value);
3449 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3450 __ Lsl(o_l, low, shift_value);
3451 } else if (op->IsShr()) {
3452 __ Lsr(o_l, low, shift_value);
3453 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3454 __ Asr(o_h, high, shift_value);
3455 } else {
3456 __ Lsr(o_l, low, shift_value);
3457 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3458 __ Lsr(o_h, high, shift_value);
3459 }
3460 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003461 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003462 break;
3463 }
3464 default:
3465 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003466 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003467 }
3468}
3469
3470void LocationsBuilderARM::VisitShl(HShl* shl) {
3471 HandleShift(shl);
3472}
3473
3474void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3475 HandleShift(shl);
3476}
3477
3478void LocationsBuilderARM::VisitShr(HShr* shr) {
3479 HandleShift(shr);
3480}
3481
3482void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3483 HandleShift(shr);
3484}
3485
3486void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3487 HandleShift(ushr);
3488}
3489
3490void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3491 HandleShift(ushr);
3492}
3493
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003494void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003495 LocationSummary* locations =
3496 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
David Brazdil6de19382016-01-08 17:37:10 +00003497 if (instruction->IsStringAlloc()) {
3498 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3499 } else {
3500 InvokeRuntimeCallingConvention calling_convention;
3501 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3502 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3503 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003504 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003505}
3506
3507void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003508 // Note: if heap poisoning is enabled, the entry point takes cares
3509 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003510 if (instruction->IsStringAlloc()) {
3511 // String is allocated through StringFactory. Call NewEmptyString entry point.
3512 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
3513 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
3514 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3515 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3516 __ blx(LR);
3517 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3518 } else {
3519 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3520 instruction,
3521 instruction->GetDexPc(),
3522 nullptr);
3523 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3524 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003525}
3526
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003527void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3528 LocationSummary* locations =
3529 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3530 InvokeRuntimeCallingConvention calling_convention;
3531 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003532 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003533 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003534 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003535}
3536
3537void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3538 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003539 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003540 // Note: if heap poisoning is enabled, the entry point takes cares
3541 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003542 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003543 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003544 instruction->GetDexPc(),
3545 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003546 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003547}
3548
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003549void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003550 LocationSummary* locations =
3551 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003552 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3553 if (location.IsStackSlot()) {
3554 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3555 } else if (location.IsDoubleStackSlot()) {
3556 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003557 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003558 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003559}
3560
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003561void InstructionCodeGeneratorARM::VisitParameterValue(
3562 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003563 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003564}
3565
3566void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3567 LocationSummary* locations =
3568 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3569 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3570}
3571
3572void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3573 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003574}
3575
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003576void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003577 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003578 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003579 locations->SetInAt(0, Location::RequiresRegister());
3580 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003581}
3582
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003583void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3584 LocationSummary* locations = not_->GetLocations();
3585 Location out = locations->Out();
3586 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003587 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003588 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003589 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003590 break;
3591
3592 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003593 __ mvn(out.AsRegisterPairLow<Register>(),
3594 ShifterOperand(in.AsRegisterPairLow<Register>()));
3595 __ mvn(out.AsRegisterPairHigh<Register>(),
3596 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003597 break;
3598
3599 default:
3600 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3601 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003602}
3603
David Brazdil66d126e2015-04-03 16:02:44 +01003604void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3605 LocationSummary* locations =
3606 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3607 locations->SetInAt(0, Location::RequiresRegister());
3608 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3609}
3610
3611void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003612 LocationSummary* locations = bool_not->GetLocations();
3613 Location out = locations->Out();
3614 Location in = locations->InAt(0);
3615 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3616}
3617
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003618void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003619 LocationSummary* locations =
3620 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003621 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003622 case Primitive::kPrimBoolean:
3623 case Primitive::kPrimByte:
3624 case Primitive::kPrimShort:
3625 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003626 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00003627 case Primitive::kPrimLong: {
3628 locations->SetInAt(0, Location::RequiresRegister());
3629 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003630 // Output overlaps because it is written before doing the low comparison.
3631 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003632 break;
3633 }
3634 case Primitive::kPrimFloat:
3635 case Primitive::kPrimDouble: {
3636 locations->SetInAt(0, Location::RequiresFpuRegister());
3637 locations->SetInAt(1, Location::RequiresFpuRegister());
3638 locations->SetOut(Location::RequiresRegister());
3639 break;
3640 }
3641 default:
3642 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3643 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003644}
3645
3646void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003647 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003648 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003649 Location left = locations->InAt(0);
3650 Location right = locations->InAt(1);
3651
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003652 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003653 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00003654 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00003655 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003656 case Primitive::kPrimBoolean:
3657 case Primitive::kPrimByte:
3658 case Primitive::kPrimShort:
3659 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003660 case Primitive::kPrimInt: {
3661 __ LoadImmediate(out, 0);
3662 __ cmp(left.AsRegister<Register>(),
3663 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
3664 less_cond = LT;
3665 break;
3666 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003667 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003668 __ cmp(left.AsRegisterPairHigh<Register>(),
3669 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003670 __ b(&less, LT);
3671 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003672 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003673 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003674 __ cmp(left.AsRegisterPairLow<Register>(),
3675 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003676 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00003677 break;
3678 }
3679 case Primitive::kPrimFloat:
3680 case Primitive::kPrimDouble: {
3681 __ LoadImmediate(out, 0);
3682 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003683 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003684 } else {
3685 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3686 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3687 }
3688 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003689 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003690 break;
3691 }
3692 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003693 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00003694 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003695 }
Aart Bika19616e2016-02-01 18:57:58 -08003696
Calin Juravleddb7df22014-11-25 20:56:51 +00003697 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00003698 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00003699
3700 __ Bind(&greater);
3701 __ LoadImmediate(out, 1);
3702 __ b(&done);
3703
3704 __ Bind(&less);
3705 __ LoadImmediate(out, -1);
3706
3707 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003708}
3709
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003710void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003711 LocationSummary* locations =
3712 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01003713 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003714 locations->SetInAt(i, Location::Any());
3715 }
3716 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003717}
3718
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003719void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003720 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003721}
3722
Roland Levillainc9285912015-12-18 10:38:42 +00003723void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3724 // TODO (ported from quick): revisit ARM barrier kinds.
3725 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00003726 switch (kind) {
3727 case MemBarrierKind::kAnyStore:
3728 case MemBarrierKind::kLoadAny:
3729 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003730 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003731 break;
3732 }
3733 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003734 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003735 break;
3736 }
3737 default:
3738 LOG(FATAL) << "Unexpected memory barrier " << kind;
3739 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003740 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003741}
3742
3743void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3744 uint32_t offset,
3745 Register out_lo,
3746 Register out_hi) {
3747 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003748 // Ensure `out_lo` is different from `addr`, so that loading
3749 // `offset` into `out_lo` does not clutter `addr`.
3750 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003751 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003752 __ add(IP, addr, ShifterOperand(out_lo));
3753 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003754 }
3755 __ ldrexd(out_lo, out_hi, addr);
3756}
3757
3758void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3759 uint32_t offset,
3760 Register value_lo,
3761 Register value_hi,
3762 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003763 Register temp2,
3764 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003765 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003766 if (offset != 0) {
3767 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003768 __ add(IP, addr, ShifterOperand(temp1));
3769 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003770 }
3771 __ Bind(&fail);
3772 // We need a load followed by store. (The address used in a STREX instruction must
3773 // be the same as the address in the most recently executed LDREX instruction.)
3774 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003775 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003776 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003777 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003778}
3779
3780void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3781 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3782
Nicolas Geoffray39468442014-09-02 15:17:15 +01003783 LocationSummary* locations =
3784 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003785 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003786
Calin Juravle52c48962014-12-16 17:02:57 +00003787 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003788 if (Primitive::IsFloatingPointType(field_type)) {
3789 locations->SetInAt(1, Location::RequiresFpuRegister());
3790 } else {
3791 locations->SetInAt(1, Location::RequiresRegister());
3792 }
3793
Calin Juravle52c48962014-12-16 17:02:57 +00003794 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003795 bool generate_volatile = field_info.IsVolatile()
3796 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003797 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003798 bool needs_write_barrier =
3799 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003800 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003801 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003802 if (needs_write_barrier) {
3803 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003804 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003805 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003806 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003807 // - registers need to be consecutive
3808 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003809 // We don't test for ARM yet, and the assertion makes sure that we
3810 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003811 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3812
3813 locations->AddTemp(Location::RequiresRegister());
3814 locations->AddTemp(Location::RequiresRegister());
3815 if (field_type == Primitive::kPrimDouble) {
3816 // For doubles we need two more registers to copy the value.
3817 locations->AddTemp(Location::RegisterLocation(R2));
3818 locations->AddTemp(Location::RegisterLocation(R3));
3819 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003820 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003821}
3822
Calin Juravle52c48962014-12-16 17:02:57 +00003823void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003824 const FieldInfo& field_info,
3825 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003826 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3827
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003828 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003829 Register base = locations->InAt(0).AsRegister<Register>();
3830 Location value = locations->InAt(1);
3831
3832 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003833 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003834 Primitive::Type field_type = field_info.GetFieldType();
3835 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003836 bool needs_write_barrier =
3837 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003838
3839 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003840 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00003841 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003842
3843 switch (field_type) {
3844 case Primitive::kPrimBoolean:
3845 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003846 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003847 break;
3848 }
3849
3850 case Primitive::kPrimShort:
3851 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003852 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003853 break;
3854 }
3855
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003856 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003857 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003858 if (kPoisonHeapReferences && needs_write_barrier) {
3859 // Note that in the case where `value` is a null reference,
3860 // we do not enter this block, as a null reference does not
3861 // need poisoning.
3862 DCHECK_EQ(field_type, Primitive::kPrimNot);
3863 Register temp = locations->GetTemp(0).AsRegister<Register>();
3864 __ Mov(temp, value.AsRegister<Register>());
3865 __ PoisonHeapReference(temp);
3866 __ StoreToOffset(kStoreWord, temp, base, offset);
3867 } else {
3868 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3869 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003870 break;
3871 }
3872
3873 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003874 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003875 GenerateWideAtomicStore(base, offset,
3876 value.AsRegisterPairLow<Register>(),
3877 value.AsRegisterPairHigh<Register>(),
3878 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003879 locations->GetTemp(1).AsRegister<Register>(),
3880 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003881 } else {
3882 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003883 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003884 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003885 break;
3886 }
3887
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003888 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003889 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003890 break;
3891 }
3892
3893 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003894 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003895 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003896 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3897 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3898
3899 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3900
3901 GenerateWideAtomicStore(base, offset,
3902 value_reg_lo,
3903 value_reg_hi,
3904 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003905 locations->GetTemp(3).AsRegister<Register>(),
3906 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003907 } else {
3908 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003909 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003910 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003911 break;
3912 }
3913
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003914 case Primitive::kPrimVoid:
3915 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003916 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003917 }
Calin Juravle52c48962014-12-16 17:02:57 +00003918
Calin Juravle77520bc2015-01-12 18:45:46 +00003919 // Longs and doubles are handled in the switch.
3920 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3921 codegen_->MaybeRecordImplicitNullCheck(instruction);
3922 }
3923
3924 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3925 Register temp = locations->GetTemp(0).AsRegister<Register>();
3926 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003927 codegen_->MarkGCCard(
3928 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003929 }
3930
Calin Juravle52c48962014-12-16 17:02:57 +00003931 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003932 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00003933 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003934}
3935
Calin Juravle52c48962014-12-16 17:02:57 +00003936void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3937 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003938
3939 bool object_field_get_with_read_barrier =
3940 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003941 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003942 new (GetGraph()->GetArena()) LocationSummary(instruction,
3943 object_field_get_with_read_barrier ?
3944 LocationSummary::kCallOnSlowPath :
3945 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003946 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003947
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003948 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003949 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003950 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00003951 // The output overlaps in case of volatile long: we don't want the
3952 // code generated by GenerateWideAtomicLoad to overwrite the
3953 // object's location. Likewise, in the case of an object field get
3954 // with read barriers enabled, we do not want the load to overwrite
3955 // the object's location, as we need it to emit the read barrier.
3956 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
3957 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003958
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003959 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3960 locations->SetOut(Location::RequiresFpuRegister());
3961 } else {
3962 locations->SetOut(Location::RequiresRegister(),
3963 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3964 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003965 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00003966 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003967 // - registers need to be consecutive
3968 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003969 // We don't test for ARM yet, and the assertion makes sure that we
3970 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003971 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3972 locations->AddTemp(Location::RequiresRegister());
3973 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00003974 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
3975 // We need a temporary register for the read barrier marking slow
3976 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
3977 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003978 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003979}
3980
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003981Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3982 Opcode opcode) {
3983 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3984 if (constant->IsConstant() &&
3985 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3986 return Location::ConstantLocation(constant->AsConstant());
3987 }
3988 return Location::RequiresRegister();
3989}
3990
3991bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3992 Opcode opcode) {
3993 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3994 if (Primitive::Is64BitType(input_cst->GetType())) {
3995 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3996 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3997 } else {
3998 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3999 }
4000}
4001
4002bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4003 ShifterOperand so;
4004 ArmAssembler* assembler = codegen_->GetAssembler();
4005 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4006 return true;
4007 }
4008 Opcode neg_opcode = kNoOperand;
4009 switch (opcode) {
4010 case AND:
4011 neg_opcode = BIC;
4012 break;
4013 case ORR:
4014 neg_opcode = ORN;
4015 break;
4016 default:
4017 return false;
4018 }
4019 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4020}
4021
Calin Juravle52c48962014-12-16 17:02:57 +00004022void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4023 const FieldInfo& field_info) {
4024 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004025
Calin Juravle52c48962014-12-16 17:02:57 +00004026 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004027 Location base_loc = locations->InAt(0);
4028 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004029 Location out = locations->Out();
4030 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004031 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004032 Primitive::Type field_type = field_info.GetFieldType();
4033 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4034
4035 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004036 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004037 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004038 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004039
Roland Levillainc9285912015-12-18 10:38:42 +00004040 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004041 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004042 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004043
Roland Levillainc9285912015-12-18 10:38:42 +00004044 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004045 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004046 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004047
Roland Levillainc9285912015-12-18 10:38:42 +00004048 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004049 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004050 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004051
4052 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004053 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004054 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004055
4056 case Primitive::kPrimNot: {
4057 // /* HeapReference<Object> */ out = *(base + offset)
4058 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4059 Location temp_loc = locations->GetTemp(0);
4060 // Note that a potential implicit null check is handled in this
4061 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4062 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4063 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4064 if (is_volatile) {
4065 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4066 }
4067 } else {
4068 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4069 codegen_->MaybeRecordImplicitNullCheck(instruction);
4070 if (is_volatile) {
4071 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4072 }
4073 // If read barriers are enabled, emit read barriers other than
4074 // Baker's using a slow path (and also unpoison the loaded
4075 // reference, if heap poisoning is enabled).
4076 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4077 }
4078 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004079 }
4080
Roland Levillainc9285912015-12-18 10:38:42 +00004081 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004082 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004083 GenerateWideAtomicLoad(base, offset,
4084 out.AsRegisterPairLow<Register>(),
4085 out.AsRegisterPairHigh<Register>());
4086 } else {
4087 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4088 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004089 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004090
Roland Levillainc9285912015-12-18 10:38:42 +00004091 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004092 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004093 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004094
4095 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004096 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004097 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004098 Register lo = locations->GetTemp(0).AsRegister<Register>();
4099 Register hi = locations->GetTemp(1).AsRegister<Register>();
4100 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004101 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004102 __ vmovdrr(out_reg, lo, hi);
4103 } else {
4104 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004105 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004106 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004107 break;
4108 }
4109
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004110 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004111 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004112 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004113 }
Calin Juravle52c48962014-12-16 17:02:57 +00004114
Roland Levillainc9285912015-12-18 10:38:42 +00004115 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4116 // Potential implicit null checks, in the case of reference or
4117 // double fields, are handled in the previous switch statement.
4118 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004119 codegen_->MaybeRecordImplicitNullCheck(instruction);
4120 }
4121
Calin Juravle52c48962014-12-16 17:02:57 +00004122 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004123 if (field_type == Primitive::kPrimNot) {
4124 // Memory barriers, in the case of references, are also handled
4125 // in the previous switch statement.
4126 } else {
4127 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4128 }
Roland Levillain4d027112015-07-01 15:41:14 +01004129 }
Calin Juravle52c48962014-12-16 17:02:57 +00004130}
4131
4132void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4133 HandleFieldSet(instruction, instruction->GetFieldInfo());
4134}
4135
4136void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004137 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004138}
4139
4140void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4141 HandleFieldGet(instruction, instruction->GetFieldInfo());
4142}
4143
4144void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4145 HandleFieldGet(instruction, instruction->GetFieldInfo());
4146}
4147
4148void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4149 HandleFieldGet(instruction, instruction->GetFieldInfo());
4150}
4151
4152void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4153 HandleFieldGet(instruction, instruction->GetFieldInfo());
4154}
4155
4156void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4157 HandleFieldSet(instruction, instruction->GetFieldInfo());
4158}
4159
4160void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004161 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004162}
4163
Calin Juravlee460d1d2015-09-29 04:52:17 +01004164void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4165 HUnresolvedInstanceFieldGet* instruction) {
4166 FieldAccessCallingConventionARM calling_convention;
4167 codegen_->CreateUnresolvedFieldLocationSummary(
4168 instruction, instruction->GetFieldType(), calling_convention);
4169}
4170
4171void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4172 HUnresolvedInstanceFieldGet* instruction) {
4173 FieldAccessCallingConventionARM calling_convention;
4174 codegen_->GenerateUnresolvedFieldAccess(instruction,
4175 instruction->GetFieldType(),
4176 instruction->GetFieldIndex(),
4177 instruction->GetDexPc(),
4178 calling_convention);
4179}
4180
4181void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4182 HUnresolvedInstanceFieldSet* instruction) {
4183 FieldAccessCallingConventionARM calling_convention;
4184 codegen_->CreateUnresolvedFieldLocationSummary(
4185 instruction, instruction->GetFieldType(), calling_convention);
4186}
4187
4188void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4189 HUnresolvedInstanceFieldSet* instruction) {
4190 FieldAccessCallingConventionARM calling_convention;
4191 codegen_->GenerateUnresolvedFieldAccess(instruction,
4192 instruction->GetFieldType(),
4193 instruction->GetFieldIndex(),
4194 instruction->GetDexPc(),
4195 calling_convention);
4196}
4197
4198void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4199 HUnresolvedStaticFieldGet* instruction) {
4200 FieldAccessCallingConventionARM calling_convention;
4201 codegen_->CreateUnresolvedFieldLocationSummary(
4202 instruction, instruction->GetFieldType(), calling_convention);
4203}
4204
4205void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4206 HUnresolvedStaticFieldGet* instruction) {
4207 FieldAccessCallingConventionARM calling_convention;
4208 codegen_->GenerateUnresolvedFieldAccess(instruction,
4209 instruction->GetFieldType(),
4210 instruction->GetFieldIndex(),
4211 instruction->GetDexPc(),
4212 calling_convention);
4213}
4214
4215void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4216 HUnresolvedStaticFieldSet* instruction) {
4217 FieldAccessCallingConventionARM calling_convention;
4218 codegen_->CreateUnresolvedFieldLocationSummary(
4219 instruction, instruction->GetFieldType(), calling_convention);
4220}
4221
4222void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4223 HUnresolvedStaticFieldSet* instruction) {
4224 FieldAccessCallingConventionARM calling_convention;
4225 codegen_->GenerateUnresolvedFieldAccess(instruction,
4226 instruction->GetFieldType(),
4227 instruction->GetFieldIndex(),
4228 instruction->GetDexPc(),
4229 calling_convention);
4230}
4231
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004232void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004233 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4234 ? LocationSummary::kCallOnSlowPath
4235 : LocationSummary::kNoCall;
4236 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004237 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004238 if (instruction->HasUses()) {
4239 locations->SetOut(Location::SameAsFirstInput());
4240 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004241}
4242
Calin Juravle2ae48182016-03-16 14:05:09 +00004243void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4244 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004245 return;
4246 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004247 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004248
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004249 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004250 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004251}
4252
Calin Juravle2ae48182016-03-16 14:05:09 +00004253void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004254 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004255 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004256
4257 LocationSummary* locations = instruction->GetLocations();
4258 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004259
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004260 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004261}
4262
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004263void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004264 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004265}
4266
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004267void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004268 bool object_array_get_with_read_barrier =
4269 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004270 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004271 new (GetGraph()->GetArena()) LocationSummary(instruction,
4272 object_array_get_with_read_barrier ?
4273 LocationSummary::kCallOnSlowPath :
4274 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004275 locations->SetInAt(0, Location::RequiresRegister());
4276 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004277 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4278 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4279 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004280 // The output overlaps in the case of an object array get with
4281 // read barriers enabled: we do not want the move to overwrite the
4282 // array's location, as we need it to emit the read barrier.
4283 locations->SetOut(
4284 Location::RequiresRegister(),
4285 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004286 }
Roland Levillainc9285912015-12-18 10:38:42 +00004287 // We need a temporary register for the read barrier marking slow
4288 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4289 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4290 locations->AddTemp(Location::RequiresRegister());
4291 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004292}
4293
4294void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4295 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004296 Location obj_loc = locations->InAt(0);
4297 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004298 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004299 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004300 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004301
Roland Levillainc9285912015-12-18 10:38:42 +00004302 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004303 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004304 case Primitive::kPrimBoolean: {
Roland Levillainc9285912015-12-18 10:38:42 +00004305 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004306 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004307 size_t offset =
4308 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004309 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4310 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004311 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004312 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4313 }
4314 break;
4315 }
4316
4317 case Primitive::kPrimByte: {
Roland Levillainc9285912015-12-18 10:38:42 +00004318 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004319 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004320 size_t offset =
4321 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004322 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4323 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004324 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004325 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4326 }
4327 break;
4328 }
4329
4330 case Primitive::kPrimShort: {
Roland Levillainc9285912015-12-18 10:38:42 +00004331 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004332 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004333 size_t offset =
4334 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004335 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4336 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004337 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004338 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4339 }
4340 break;
4341 }
4342
4343 case Primitive::kPrimChar: {
Roland Levillainc9285912015-12-18 10:38:42 +00004344 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004345 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004346 size_t offset =
4347 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004348 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4349 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004350 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004351 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4352 }
4353 break;
4354 }
4355
Roland Levillainc9285912015-12-18 10:38:42 +00004356 case Primitive::kPrimInt: {
Roland Levillainc9285912015-12-18 10:38:42 +00004357 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004359 size_t offset =
4360 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004361 __ LoadFromOffset(kLoadWord, out, obj, offset);
4362 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004363 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004364 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4365 }
4366 break;
4367 }
4368
Roland Levillainc9285912015-12-18 10:38:42 +00004369 case Primitive::kPrimNot: {
4370 static_assert(
4371 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4372 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00004373 // /* HeapReference<Object> */ out =
4374 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4375 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4376 Location temp = locations->GetTemp(0);
4377 // Note that a potential implicit null check is handled in this
4378 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4379 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4380 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4381 } else {
4382 Register out = out_loc.AsRegister<Register>();
4383 if (index.IsConstant()) {
4384 size_t offset =
4385 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4386 __ LoadFromOffset(kLoadWord, out, obj, offset);
4387 codegen_->MaybeRecordImplicitNullCheck(instruction);
4388 // If read barriers are enabled, emit read barriers other than
4389 // Baker's using a slow path (and also unpoison the loaded
4390 // reference, if heap poisoning is enabled).
4391 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4392 } else {
4393 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4394 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4395 codegen_->MaybeRecordImplicitNullCheck(instruction);
4396 // If read barriers are enabled, emit read barriers other than
4397 // Baker's using a slow path (and also unpoison the loaded
4398 // reference, if heap poisoning is enabled).
4399 codegen_->MaybeGenerateReadBarrierSlow(
4400 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4401 }
4402 }
4403 break;
4404 }
4405
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004406 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004407 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004408 size_t offset =
4409 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004410 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004411 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004412 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004413 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004414 }
4415 break;
4416 }
4417
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004418 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00004419 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004420 if (index.IsConstant()) {
4421 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004422 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004423 } else {
4424 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00004425 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004426 }
4427 break;
4428 }
4429
4430 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00004431 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004432 if (index.IsConstant()) {
4433 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004434 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004435 } else {
4436 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004437 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004438 }
4439 break;
4440 }
4441
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004442 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004443 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004444 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004445 }
Roland Levillain4d027112015-07-01 15:41:14 +01004446
4447 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00004448 // Potential implicit null checks, in the case of reference
4449 // arrays, are handled in the previous switch statement.
4450 } else {
4451 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004452 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004453}
4454
4455void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004456 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004457
4458 bool needs_write_barrier =
4459 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004460 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4461 bool object_array_set_with_read_barrier =
4462 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004463
Nicolas Geoffray39468442014-09-02 15:17:15 +01004464 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004465 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004466 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4467 LocationSummary::kCallOnSlowPath :
4468 LocationSummary::kNoCall);
4469
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004470 locations->SetInAt(0, Location::RequiresRegister());
4471 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4472 if (Primitive::IsFloatingPointType(value_type)) {
4473 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004474 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004475 locations->SetInAt(2, Location::RequiresRegister());
4476 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004477 if (needs_write_barrier) {
4478 // Temporary registers for the write barrier.
4479 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004480 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004481 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004482}
4483
4484void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4485 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004486 Location array_loc = locations->InAt(0);
4487 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004488 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004489 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004490 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004491 bool needs_write_barrier =
4492 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004493
4494 switch (value_type) {
4495 case Primitive::kPrimBoolean:
4496 case Primitive::kPrimByte: {
4497 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004498 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004499 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004500 size_t offset =
4501 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004502 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004503 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004504 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004505 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4506 }
4507 break;
4508 }
4509
4510 case Primitive::kPrimShort:
4511 case Primitive::kPrimChar: {
4512 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004513 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004514 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004515 size_t offset =
4516 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004517 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004518 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004519 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004520 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4521 }
4522 break;
4523 }
4524
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004525 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004526 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004527 Location value_loc = locations->InAt(2);
4528 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004529 Register source = value;
4530
4531 if (instruction->InputAt(2)->IsNullConstant()) {
4532 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004533 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004534 size_t offset =
4535 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004536 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004537 } else {
4538 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004539 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004540 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004541 }
Roland Levillain1407ee72016-01-08 15:56:19 +00004542 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00004543 DCHECK(!needs_write_barrier);
4544 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004545 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004546 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004547
4548 DCHECK(needs_write_barrier);
4549 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4550 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4551 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4552 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4553 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4554 Label done;
4555 SlowPathCode* slow_path = nullptr;
4556
Roland Levillain3b359c72015-11-17 19:35:12 +00004557 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004558 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4559 codegen_->AddSlowPath(slow_path);
4560 if (instruction->GetValueCanBeNull()) {
4561 Label non_zero;
4562 __ CompareAndBranchIfNonZero(value, &non_zero);
4563 if (index.IsConstant()) {
4564 size_t offset =
4565 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4566 __ StoreToOffset(kStoreWord, value, array, offset);
4567 } else {
4568 DCHECK(index.IsRegister()) << index;
4569 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4570 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4571 }
4572 codegen_->MaybeRecordImplicitNullCheck(instruction);
4573 __ b(&done);
4574 __ Bind(&non_zero);
4575 }
4576
Roland Levillain3b359c72015-11-17 19:35:12 +00004577 if (kEmitCompilerReadBarrier) {
4578 // When read barriers are enabled, the type checking
4579 // instrumentation requires two read barriers:
4580 //
4581 // __ Mov(temp2, temp1);
4582 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4583 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004584 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004585 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4586 //
4587 // // /* HeapReference<Class> */ temp2 = value->klass_
4588 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004589 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004590 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4591 //
4592 // __ cmp(temp1, ShifterOperand(temp2));
4593 //
4594 // However, the second read barrier may trash `temp`, as it
4595 // is a temporary register, and as such would not be saved
4596 // along with live registers before calling the runtime (nor
4597 // restored afterwards). So in this case, we bail out and
4598 // delegate the work to the array set slow path.
4599 //
4600 // TODO: Extend the register allocator to support a new
4601 // "(locally) live temp" location so as to avoid always
4602 // going into the slow path when read barriers are enabled.
4603 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004604 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004605 // /* HeapReference<Class> */ temp1 = array->klass_
4606 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4607 codegen_->MaybeRecordImplicitNullCheck(instruction);
4608 __ MaybeUnpoisonHeapReference(temp1);
4609
4610 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4611 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4612 // /* HeapReference<Class> */ temp2 = value->klass_
4613 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4614 // If heap poisoning is enabled, no need to unpoison `temp1`
4615 // nor `temp2`, as we are comparing two poisoned references.
4616 __ cmp(temp1, ShifterOperand(temp2));
4617
4618 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4619 Label do_put;
4620 __ b(&do_put, EQ);
4621 // If heap poisoning is enabled, the `temp1` reference has
4622 // not been unpoisoned yet; unpoison it now.
4623 __ MaybeUnpoisonHeapReference(temp1);
4624
4625 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4626 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4627 // If heap poisoning is enabled, no need to unpoison
4628 // `temp1`, as we are comparing against null below.
4629 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4630 __ Bind(&do_put);
4631 } else {
4632 __ b(slow_path->GetEntryLabel(), NE);
4633 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004634 }
4635 }
4636
4637 if (kPoisonHeapReferences) {
4638 // Note that in the case where `value` is a null reference,
4639 // we do not enter this block, as a null reference does not
4640 // need poisoning.
4641 DCHECK_EQ(value_type, Primitive::kPrimNot);
4642 __ Mov(temp1, value);
4643 __ PoisonHeapReference(temp1);
4644 source = temp1;
4645 }
4646
4647 if (index.IsConstant()) {
4648 size_t offset =
4649 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4650 __ StoreToOffset(kStoreWord, source, array, offset);
4651 } else {
4652 DCHECK(index.IsRegister()) << index;
4653 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4654 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4655 }
4656
Roland Levillain3b359c72015-11-17 19:35:12 +00004657 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004658 codegen_->MaybeRecordImplicitNullCheck(instruction);
4659 }
4660
4661 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4662
4663 if (done.IsLinked()) {
4664 __ Bind(&done);
4665 }
4666
4667 if (slow_path != nullptr) {
4668 __ Bind(slow_path->GetExitLabel());
4669 }
4670
4671 break;
4672 }
4673
4674 case Primitive::kPrimInt: {
4675 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4676 Register value = locations->InAt(2).AsRegister<Register>();
4677 if (index.IsConstant()) {
4678 size_t offset =
4679 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4680 __ StoreToOffset(kStoreWord, value, array, offset);
4681 } else {
4682 DCHECK(index.IsRegister()) << index;
4683 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4684 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4685 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004686 break;
4687 }
4688
4689 case Primitive::kPrimLong: {
4690 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004691 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004692 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004693 size_t offset =
4694 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004695 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004696 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004697 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004698 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004699 }
4700 break;
4701 }
4702
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004703 case Primitive::kPrimFloat: {
4704 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4705 Location value = locations->InAt(2);
4706 DCHECK(value.IsFpuRegister());
4707 if (index.IsConstant()) {
4708 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004709 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004710 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004711 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004712 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4713 }
4714 break;
4715 }
4716
4717 case Primitive::kPrimDouble: {
4718 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4719 Location value = locations->InAt(2);
4720 DCHECK(value.IsFpuRegisterPair());
4721 if (index.IsConstant()) {
4722 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004723 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004724 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004725 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004726 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4727 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004728
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004729 break;
4730 }
4731
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004732 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004733 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004734 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004735 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004736
Roland Levillain80e67092016-01-08 16:04:55 +00004737 // Objects are handled in the switch.
4738 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004739 codegen_->MaybeRecordImplicitNullCheck(instruction);
4740 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004741}
4742
4743void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004744 LocationSummary* locations =
4745 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004746 locations->SetInAt(0, Location::RequiresRegister());
4747 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004748}
4749
4750void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4751 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01004752 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004753 Register obj = locations->InAt(0).AsRegister<Register>();
4754 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004755 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004756 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004757}
4758
4759void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004760 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4761 ? LocationSummary::kCallOnSlowPath
4762 : LocationSummary::kNoCall;
4763 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004764 locations->SetInAt(0, Location::RequiresRegister());
4765 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004766 if (instruction->HasUses()) {
4767 locations->SetOut(Location::SameAsFirstInput());
4768 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004769}
4770
4771void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4772 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004773 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004774 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004775 codegen_->AddSlowPath(slow_path);
4776
Roland Levillain271ab9c2014-11-27 15:23:57 +00004777 Register index = locations->InAt(0).AsRegister<Register>();
4778 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004779
4780 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004781 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004782}
4783
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004784void CodeGeneratorARM::MarkGCCard(Register temp,
4785 Register card,
4786 Register object,
4787 Register value,
4788 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004789 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004790 if (can_be_null) {
4791 __ CompareAndBranchIfZero(value, &is_null);
4792 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004793 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4794 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4795 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004796 if (can_be_null) {
4797 __ Bind(&is_null);
4798 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004799}
4800
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004801void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004802 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004803}
4804
4805void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004806 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4807}
4808
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004809void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4810 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4811}
4812
4813void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004814 HBasicBlock* block = instruction->GetBlock();
4815 if (block->GetLoopInformation() != nullptr) {
4816 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4817 // The back edge will generate the suspend check.
4818 return;
4819 }
4820 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4821 // The goto will generate the suspend check.
4822 return;
4823 }
4824 GenerateSuspendCheck(instruction, nullptr);
4825}
4826
4827void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4828 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004829 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004830 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4831 if (slow_path == nullptr) {
4832 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4833 instruction->SetSlowPath(slow_path);
4834 codegen_->AddSlowPath(slow_path);
4835 if (successor != nullptr) {
4836 DCHECK(successor->IsLoopHeader());
4837 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4838 }
4839 } else {
4840 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4841 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004842
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004843 __ LoadFromOffset(
4844 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004845 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004846 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004847 __ Bind(slow_path->GetReturnLabel());
4848 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004849 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004850 __ b(slow_path->GetEntryLabel());
4851 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004852}
4853
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004854ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4855 return codegen_->GetAssembler();
4856}
4857
4858void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004859 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004860 Location source = move->GetSource();
4861 Location destination = move->GetDestination();
4862
4863 if (source.IsRegister()) {
4864 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004865 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004866 } else if (destination.IsFpuRegister()) {
4867 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004868 } else {
4869 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004870 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004871 SP, destination.GetStackIndex());
4872 }
4873 } else if (source.IsStackSlot()) {
4874 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004875 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004876 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004877 } else if (destination.IsFpuRegister()) {
4878 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004879 } else {
4880 DCHECK(destination.IsStackSlot());
4881 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4882 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4883 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004884 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004885 if (destination.IsRegister()) {
4886 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
4887 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004888 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004889 } else {
4890 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004891 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4892 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004893 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004894 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004895 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4896 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004897 } else if (destination.IsRegisterPair()) {
4898 DCHECK(ExpectedPairLayout(destination));
4899 __ LoadFromOffset(
4900 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4901 } else {
4902 DCHECK(destination.IsFpuRegisterPair()) << destination;
4903 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4904 SP,
4905 source.GetStackIndex());
4906 }
4907 } else if (source.IsRegisterPair()) {
4908 if (destination.IsRegisterPair()) {
4909 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4910 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004911 } else if (destination.IsFpuRegisterPair()) {
4912 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4913 source.AsRegisterPairLow<Register>(),
4914 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004915 } else {
4916 DCHECK(destination.IsDoubleStackSlot()) << destination;
4917 DCHECK(ExpectedPairLayout(source));
4918 __ StoreToOffset(
4919 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4920 }
4921 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004922 if (destination.IsRegisterPair()) {
4923 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4924 destination.AsRegisterPairHigh<Register>(),
4925 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4926 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004927 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4928 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4929 } else {
4930 DCHECK(destination.IsDoubleStackSlot()) << destination;
4931 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4932 SP,
4933 destination.GetStackIndex());
4934 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004935 } else {
4936 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004937 HConstant* constant = source.GetConstant();
4938 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4939 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004940 if (destination.IsRegister()) {
4941 __ LoadImmediate(destination.AsRegister<Register>(), value);
4942 } else {
4943 DCHECK(destination.IsStackSlot());
4944 __ LoadImmediate(IP, value);
4945 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4946 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004947 } else if (constant->IsLongConstant()) {
4948 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004949 if (destination.IsRegisterPair()) {
4950 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4951 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004952 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004953 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004954 __ LoadImmediate(IP, Low32Bits(value));
4955 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4956 __ LoadImmediate(IP, High32Bits(value));
4957 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4958 }
4959 } else if (constant->IsDoubleConstant()) {
4960 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004961 if (destination.IsFpuRegisterPair()) {
4962 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004963 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004964 DCHECK(destination.IsDoubleStackSlot()) << destination;
4965 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004966 __ LoadImmediate(IP, Low32Bits(int_value));
4967 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4968 __ LoadImmediate(IP, High32Bits(int_value));
4969 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4970 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004971 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004972 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004973 float value = constant->AsFloatConstant()->GetValue();
4974 if (destination.IsFpuRegister()) {
4975 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4976 } else {
4977 DCHECK(destination.IsStackSlot());
4978 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4979 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4980 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004981 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004982 }
4983}
4984
4985void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4986 __ Mov(IP, reg);
4987 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4988 __ StoreToOffset(kStoreWord, IP, SP, mem);
4989}
4990
4991void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4992 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4993 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4994 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4995 SP, mem1 + stack_offset);
4996 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4997 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4998 SP, mem2 + stack_offset);
4999 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5000}
5001
5002void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005003 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005004 Location source = move->GetSource();
5005 Location destination = move->GetDestination();
5006
5007 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005008 DCHECK_NE(source.AsRegister<Register>(), IP);
5009 DCHECK_NE(destination.AsRegister<Register>(), IP);
5010 __ Mov(IP, source.AsRegister<Register>());
5011 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5012 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005013 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005014 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005015 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005016 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005017 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5018 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005019 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005020 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005021 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005022 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005023 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005024 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005025 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005026 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005027 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5028 destination.AsRegisterPairHigh<Register>(),
5029 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005030 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005031 Register low_reg = source.IsRegisterPair()
5032 ? source.AsRegisterPairLow<Register>()
5033 : destination.AsRegisterPairLow<Register>();
5034 int mem = source.IsRegisterPair()
5035 ? destination.GetStackIndex()
5036 : source.GetStackIndex();
5037 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005038 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005039 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005040 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005041 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005042 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5043 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005044 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005045 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005046 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005047 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5048 DRegister reg = source.IsFpuRegisterPair()
5049 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5050 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5051 int mem = source.IsFpuRegisterPair()
5052 ? destination.GetStackIndex()
5053 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005054 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005055 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005056 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005057 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5058 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5059 : destination.AsFpuRegister<SRegister>();
5060 int mem = source.IsFpuRegister()
5061 ? destination.GetStackIndex()
5062 : source.GetStackIndex();
5063
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005064 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005065 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005066 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005067 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005068 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5069 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005070 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005071 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005072 }
5073}
5074
5075void ParallelMoveResolverARM::SpillScratch(int reg) {
5076 __ Push(static_cast<Register>(reg));
5077}
5078
5079void ParallelMoveResolverARM::RestoreScratch(int reg) {
5080 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005081}
5082
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005083HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5084 HLoadClass::LoadKind desired_class_load_kind) {
5085 if (kEmitCompilerReadBarrier) {
5086 switch (desired_class_load_kind) {
5087 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5088 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5089 case HLoadClass::LoadKind::kBootImageAddress:
5090 // TODO: Implement for read barrier.
5091 return HLoadClass::LoadKind::kDexCacheViaMethod;
5092 default:
5093 break;
5094 }
5095 }
5096 switch (desired_class_load_kind) {
5097 case HLoadClass::LoadKind::kReferrersClass:
5098 break;
5099 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5100 DCHECK(!GetCompilerOptions().GetCompilePic());
5101 break;
5102 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5103 DCHECK(GetCompilerOptions().GetCompilePic());
5104 break;
5105 case HLoadClass::LoadKind::kBootImageAddress:
5106 break;
5107 case HLoadClass::LoadKind::kDexCacheAddress:
5108 DCHECK(Runtime::Current()->UseJitCompilation());
5109 break;
5110 case HLoadClass::LoadKind::kDexCachePcRelative:
5111 DCHECK(!Runtime::Current()->UseJitCompilation());
5112 // We disable pc-relative load when there is an irreducible loop, as the optimization
5113 // is incompatible with it.
5114 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5115 // with irreducible loops.
5116 if (GetGraph()->HasIrreducibleLoops()) {
5117 return HLoadClass::LoadKind::kDexCacheViaMethod;
5118 }
5119 break;
5120 case HLoadClass::LoadKind::kDexCacheViaMethod:
5121 break;
5122 }
5123 return desired_class_load_kind;
5124}
5125
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005126void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005127 if (cls->NeedsAccessCheck()) {
5128 InvokeRuntimeCallingConvention calling_convention;
5129 CodeGenerator::CreateLoadClassLocationSummary(
5130 cls,
5131 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5132 Location::RegisterLocation(R0),
5133 /* code_generator_supports_read_barrier */ true);
5134 return;
5135 }
5136
5137 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
5138 ? LocationSummary::kCallOnSlowPath
5139 : LocationSummary::kNoCall;
5140 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
5141 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5142 if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
5143 load_kind == HLoadClass::LoadKind::kDexCacheViaMethod ||
5144 load_kind == HLoadClass::LoadKind::kDexCachePcRelative) {
5145 locations->SetInAt(0, Location::RequiresRegister());
5146 }
5147 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005148}
5149
5150void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005151 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005152 if (cls->NeedsAccessCheck()) {
5153 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5154 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5155 cls,
5156 cls->GetDexPc(),
5157 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005158 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005159 return;
5160 }
5161
Roland Levillain3b359c72015-11-17 19:35:12 +00005162 Location out_loc = locations->Out();
5163 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005164
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005165 bool generate_null_check = false;
5166 switch (cls->GetLoadKind()) {
5167 case HLoadClass::LoadKind::kReferrersClass: {
5168 DCHECK(!cls->CanCallRuntime());
5169 DCHECK(!cls->MustGenerateClinitCheck());
5170 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5171 Register current_method = locations->InAt(0).AsRegister<Register>();
5172 GenerateGcRootFieldLoad(
5173 cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5174 break;
5175 }
5176 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
5177 DCHECK(!kEmitCompilerReadBarrier);
5178 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5179 cls->GetTypeIndex()));
5180 break;
5181 }
5182 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5183 DCHECK(!kEmitCompilerReadBarrier);
5184 CodeGeneratorARM::PcRelativePatchInfo* labels =
5185 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5186 __ BindTrackedLabel(&labels->movw_label);
5187 __ movw(out, /* placeholder */ 0u);
5188 __ BindTrackedLabel(&labels->movt_label);
5189 __ movt(out, /* placeholder */ 0u);
5190 __ BindTrackedLabel(&labels->add_pc_label);
5191 __ add(out, out, ShifterOperand(PC));
5192 break;
5193 }
5194 case HLoadClass::LoadKind::kBootImageAddress: {
5195 DCHECK(!kEmitCompilerReadBarrier);
5196 DCHECK_NE(cls->GetAddress(), 0u);
5197 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5198 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5199 break;
5200 }
5201 case HLoadClass::LoadKind::kDexCacheAddress: {
5202 DCHECK_NE(cls->GetAddress(), 0u);
5203 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5204 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5205 // a 128B range. To try and reduce the number of literals if we load multiple types,
5206 // simply split the dex cache address to a 128B aligned base loaded from a literal
5207 // and the remaining offset embedded in the load.
5208 static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
5209 DCHECK_ALIGNED(cls->GetAddress(), 4u);
5210 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5211 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5212 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5213 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5214 // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
5215 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5216 generate_null_check = !cls->IsInDexCache();
5217 break;
5218 }
5219 case HLoadClass::LoadKind::kDexCachePcRelative: {
5220 Register base_reg = locations->InAt(0).AsRegister<Register>();
5221 HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase();
5222 int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset();
5223 // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
5224 GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset);
5225 generate_null_check = !cls->IsInDexCache();
5226 break;
5227 }
5228 case HLoadClass::LoadKind::kDexCacheViaMethod: {
5229 // /* GcRoot<mirror::Class>[] */ out =
5230 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
5231 Register current_method = locations->InAt(0).AsRegister<Register>();
5232 __ LoadFromOffset(kLoadWord,
5233 out,
5234 current_method,
5235 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5236 // /* GcRoot<mirror::Class> */ out = out[type_index]
5237 size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5238 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5239 generate_null_check = !cls->IsInDexCache();
5240 }
5241 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005242
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005243 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5244 DCHECK(cls->CanCallRuntime());
5245 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5246 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5247 codegen_->AddSlowPath(slow_path);
5248 if (generate_null_check) {
5249 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5250 }
5251 if (cls->MustGenerateClinitCheck()) {
5252 GenerateClassInitializationCheck(slow_path, out);
5253 } else {
5254 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005255 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005256 }
5257}
5258
5259void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5260 LocationSummary* locations =
5261 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5262 locations->SetInAt(0, Location::RequiresRegister());
5263 if (check->HasUses()) {
5264 locations->SetOut(Location::SameAsFirstInput());
5265 }
5266}
5267
5268void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005269 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005270 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005271 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005272 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005273 GenerateClassInitializationCheck(slow_path,
5274 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005275}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005276
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005277void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005278 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005279 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5280 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5281 __ b(slow_path->GetEntryLabel(), LT);
5282 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5283 // properly. Therefore, we do a memory fence.
5284 __ dmb(ISH);
5285 __ Bind(slow_path->GetExitLabel());
5286}
5287
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005288HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5289 HLoadString::LoadKind desired_string_load_kind) {
5290 if (kEmitCompilerReadBarrier) {
5291 switch (desired_string_load_kind) {
5292 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5293 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5294 case HLoadString::LoadKind::kBootImageAddress:
5295 // TODO: Implement for read barrier.
5296 return HLoadString::LoadKind::kDexCacheViaMethod;
5297 default:
5298 break;
5299 }
5300 }
5301 switch (desired_string_load_kind) {
5302 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5303 DCHECK(!GetCompilerOptions().GetCompilePic());
5304 break;
5305 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5306 DCHECK(GetCompilerOptions().GetCompilePic());
5307 break;
5308 case HLoadString::LoadKind::kBootImageAddress:
5309 break;
5310 case HLoadString::LoadKind::kDexCacheAddress:
Calin Juravleffc87072016-04-20 14:22:09 +01005311 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005312 break;
5313 case HLoadString::LoadKind::kDexCachePcRelative:
Calin Juravleffc87072016-04-20 14:22:09 +01005314 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005315 // We disable pc-relative load when there is an irreducible loop, as the optimization
5316 // is incompatible with it.
5317 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5318 // with irreducible loops.
5319 if (GetGraph()->HasIrreducibleLoops()) {
5320 return HLoadString::LoadKind::kDexCacheViaMethod;
5321 }
5322 break;
5323 case HLoadString::LoadKind::kDexCacheViaMethod:
5324 break;
5325 }
5326 return desired_string_load_kind;
5327}
5328
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005329void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005330 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005331 ? LocationSummary::kCallOnSlowPath
5332 : LocationSummary::kNoCall;
5333 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005334 HLoadString::LoadKind load_kind = load->GetLoadKind();
5335 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5336 load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5337 locations->SetInAt(0, Location::RequiresRegister());
5338 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005339 locations->SetOut(Location::RequiresRegister());
5340}
5341
5342void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005343 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005344 Location out_loc = locations->Out();
5345 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005346
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005347 switch (load->GetLoadKind()) {
5348 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5349 DCHECK(!kEmitCompilerReadBarrier);
5350 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5351 load->GetStringIndex()));
5352 return; // No dex cache slow path.
5353 }
5354 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5355 DCHECK(!kEmitCompilerReadBarrier);
5356 CodeGeneratorARM::PcRelativePatchInfo* labels =
5357 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5358 __ BindTrackedLabel(&labels->movw_label);
5359 __ movw(out, /* placeholder */ 0u);
5360 __ BindTrackedLabel(&labels->movt_label);
5361 __ movt(out, /* placeholder */ 0u);
5362 __ BindTrackedLabel(&labels->add_pc_label);
5363 __ add(out, out, ShifterOperand(PC));
5364 return; // No dex cache slow path.
5365 }
5366 case HLoadString::LoadKind::kBootImageAddress: {
5367 DCHECK(!kEmitCompilerReadBarrier);
5368 DCHECK_NE(load->GetAddress(), 0u);
5369 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5370 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5371 return; // No dex cache slow path.
5372 }
5373 case HLoadString::LoadKind::kDexCacheAddress: {
5374 DCHECK_NE(load->GetAddress(), 0u);
5375 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5376 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5377 // a 128B range. To try and reduce the number of literals if we load multiple strings,
5378 // simply split the dex cache address to a 128B aligned base loaded from a literal
5379 // and the remaining offset embedded in the load.
5380 static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5381 DCHECK_ALIGNED(load->GetAddress(), 4u);
5382 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5383 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5384 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5385 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005386 // /* GcRoot<mirror::String> */ out = *(base_address + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005387 GenerateGcRootFieldLoad(load, out_loc, out, offset);
5388 break;
5389 }
5390 case HLoadString::LoadKind::kDexCachePcRelative: {
5391 Register base_reg = locations->InAt(0).AsRegister<Register>();
5392 HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5393 int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005394 // /* GcRoot<mirror::String> */ out = *(dex_cache_arrays_base + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005395 GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5396 break;
5397 }
5398 case HLoadString::LoadKind::kDexCacheViaMethod: {
5399 Register current_method = locations->InAt(0).AsRegister<Register>();
5400
5401 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5402 GenerateGcRootFieldLoad(
5403 load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5404 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5405 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5406 // /* GcRoot<mirror::String> */ out = out[string_index]
5407 GenerateGcRootFieldLoad(
5408 load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5409 break;
5410 }
5411 default:
5412 LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5413 UNREACHABLE();
5414 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005415
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005416 if (!load->IsInDexCache()) {
5417 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5418 codegen_->AddSlowPath(slow_path);
5419 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5420 __ Bind(slow_path->GetExitLabel());
5421 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005422}
5423
David Brazdilcb1c0552015-08-04 16:22:25 +01005424static int32_t GetExceptionTlsOffset() {
5425 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5426}
5427
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005428void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5429 LocationSummary* locations =
5430 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5431 locations->SetOut(Location::RequiresRegister());
5432}
5433
5434void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005435 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005436 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5437}
5438
5439void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5440 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5441}
5442
5443void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005444 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005445 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005446}
5447
5448void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5449 LocationSummary* locations =
5450 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5451 InvokeRuntimeCallingConvention calling_convention;
5452 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5453}
5454
5455void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5456 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005457 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005458 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005459}
5460
Roland Levillainc9285912015-12-18 10:38:42 +00005461static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5462 return kEmitCompilerReadBarrier &&
5463 (kUseBakerReadBarrier ||
5464 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5465 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5466 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5467}
5468
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005469void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005470 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005471 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5472 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005473 case TypeCheckKind::kExactCheck:
5474 case TypeCheckKind::kAbstractClassCheck:
5475 case TypeCheckKind::kClassHierarchyCheck:
5476 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005477 call_kind =
5478 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005479 break;
5480 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005481 case TypeCheckKind::kUnresolvedCheck:
5482 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005483 call_kind = LocationSummary::kCallOnSlowPath;
5484 break;
5485 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005486
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005487 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005488 locations->SetInAt(0, Location::RequiresRegister());
5489 locations->SetInAt(1, Location::RequiresRegister());
5490 // The "out" register is used as a temporary, so it overlaps with the inputs.
5491 // Note that TypeCheckSlowPathARM uses this register too.
5492 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5493 // When read barriers are enabled, we need a temporary register for
5494 // some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005495 if (TypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005496 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005497 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005498}
5499
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005500void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005501 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005502 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005503 Location obj_loc = locations->InAt(0);
5504 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005505 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005506 Location out_loc = locations->Out();
5507 Register out = out_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005508 Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005509 locations->GetTemp(0) :
5510 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005511 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005512 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5513 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5514 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005515 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005516 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005517
5518 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005519 // avoid null check if we know obj is not null.
5520 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005521 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005522 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005523
Roland Levillain3b359c72015-11-17 19:35:12 +00005524 // /* HeapReference<Class> */ out = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005525 GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005526
Roland Levillainc9285912015-12-18 10:38:42 +00005527 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005528 case TypeCheckKind::kExactCheck: {
5529 __ cmp(out, ShifterOperand(cls));
5530 // Classes must be equal for the instanceof to succeed.
5531 __ b(&zero, NE);
5532 __ LoadImmediate(out, 1);
5533 __ b(&done);
5534 break;
5535 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005536
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005537 case TypeCheckKind::kAbstractClassCheck: {
5538 // If the class is abstract, we eagerly fetch the super class of the
5539 // object to avoid doing a comparison we know will fail.
5540 Label loop;
5541 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005542 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005543 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005544 // If `out` is null, we use it for the result, and jump to `done`.
5545 __ CompareAndBranchIfZero(out, &done);
5546 __ cmp(out, ShifterOperand(cls));
5547 __ b(&loop, NE);
5548 __ LoadImmediate(out, 1);
5549 if (zero.IsLinked()) {
5550 __ b(&done);
5551 }
5552 break;
5553 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005554
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005555 case TypeCheckKind::kClassHierarchyCheck: {
5556 // Walk over the class hierarchy to find a match.
5557 Label loop, success;
5558 __ Bind(&loop);
5559 __ cmp(out, ShifterOperand(cls));
5560 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005561 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005562 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005563 __ CompareAndBranchIfNonZero(out, &loop);
5564 // If `out` is null, we use it for the result, and jump to `done`.
5565 __ b(&done);
5566 __ Bind(&success);
5567 __ LoadImmediate(out, 1);
5568 if (zero.IsLinked()) {
5569 __ b(&done);
5570 }
5571 break;
5572 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005573
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005574 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005575 // Do an exact check.
5576 Label exact_check;
5577 __ cmp(out, ShifterOperand(cls));
5578 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005579 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005580 // /* HeapReference<Class> */ out = out->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005581 GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005582 // If `out` is null, we use it for the result, and jump to `done`.
5583 __ CompareAndBranchIfZero(out, &done);
5584 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5585 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5586 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005587 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005588 __ LoadImmediate(out, 1);
5589 __ b(&done);
5590 break;
5591 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005592
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005593 case TypeCheckKind::kArrayCheck: {
5594 __ cmp(out, ShifterOperand(cls));
5595 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005596 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5597 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005598 codegen_->AddSlowPath(slow_path);
5599 __ b(slow_path->GetEntryLabel(), NE);
5600 __ LoadImmediate(out, 1);
5601 if (zero.IsLinked()) {
5602 __ b(&done);
5603 }
5604 break;
5605 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005606
Calin Juravle98893e12015-10-02 21:05:03 +01005607 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005608 case TypeCheckKind::kInterfaceCheck: {
5609 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005610 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00005611 // cases.
5612 //
5613 // We cannot directly call the InstanceofNonTrivial runtime
5614 // entry point without resorting to a type checking slow path
5615 // here (i.e. by calling InvokeRuntime directly), as it would
5616 // require to assign fixed registers for the inputs of this
5617 // HInstanceOf instruction (following the runtime calling
5618 // convention), which might be cluttered by the potential first
5619 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005620 //
5621 // TODO: Introduce a new runtime entry point taking the object
5622 // to test (instead of its class) as argument, and let it deal
5623 // with the read barrier issues. This will let us refactor this
5624 // case of the `switch` code as it was previously (with a direct
5625 // call to the runtime not using a type checking slow path).
5626 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005627 DCHECK(locations->OnlyCallsOnSlowPath());
5628 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5629 /* is_fatal */ false);
5630 codegen_->AddSlowPath(slow_path);
5631 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005632 if (zero.IsLinked()) {
5633 __ b(&done);
5634 }
5635 break;
5636 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005637 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005638
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005639 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005640 __ Bind(&zero);
5641 __ LoadImmediate(out, 0);
5642 }
5643
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005644 if (done.IsLinked()) {
5645 __ Bind(&done);
5646 }
5647
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005648 if (slow_path != nullptr) {
5649 __ Bind(slow_path->GetExitLabel());
5650 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005651}
5652
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005653void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005654 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5655 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5656
Roland Levillain3b359c72015-11-17 19:35:12 +00005657 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5658 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005659 case TypeCheckKind::kExactCheck:
5660 case TypeCheckKind::kAbstractClassCheck:
5661 case TypeCheckKind::kClassHierarchyCheck:
5662 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005663 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5664 LocationSummary::kCallOnSlowPath :
5665 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005666 break;
5667 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005668 case TypeCheckKind::kUnresolvedCheck:
5669 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005670 call_kind = LocationSummary::kCallOnSlowPath;
5671 break;
5672 }
5673
Roland Levillain3b359c72015-11-17 19:35:12 +00005674 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5675 locations->SetInAt(0, Location::RequiresRegister());
5676 locations->SetInAt(1, Location::RequiresRegister());
5677 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5678 locations->AddTemp(Location::RequiresRegister());
5679 // When read barriers are enabled, we need an additional temporary
5680 // register for some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005681 if (TypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005682 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005683 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005684}
5685
5686void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005687 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005688 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005689 Location obj_loc = locations->InAt(0);
5690 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005691 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005692 Location temp_loc = locations->GetTemp(0);
5693 Register temp = temp_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005694 Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005695 locations->GetTemp(1) :
5696 Location::NoLocation();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005697 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005698 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5699 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5700 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005701
Roland Levillain3b359c72015-11-17 19:35:12 +00005702 bool is_type_check_slow_path_fatal =
5703 (type_check_kind == TypeCheckKind::kExactCheck ||
5704 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5705 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5706 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5707 !instruction->CanThrowIntoCatchBlock();
5708 SlowPathCode* type_check_slow_path =
5709 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5710 is_type_check_slow_path_fatal);
5711 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005712
5713 Label done;
5714 // Avoid null check if we know obj is not null.
5715 if (instruction->MustDoNullCheck()) {
5716 __ CompareAndBranchIfZero(obj, &done);
5717 }
5718
Roland Levillain3b359c72015-11-17 19:35:12 +00005719 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005720 GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005721
Roland Levillain3b359c72015-11-17 19:35:12 +00005722 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005723 case TypeCheckKind::kExactCheck:
5724 case TypeCheckKind::kArrayCheck: {
5725 __ cmp(temp, ShifterOperand(cls));
5726 // Jump to slow path for throwing the exception or doing a
5727 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005728 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005729 break;
5730 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005731
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005732 case TypeCheckKind::kAbstractClassCheck: {
5733 // If the class is abstract, we eagerly fetch the super class of the
5734 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005735 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005736 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005737 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005738 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005739
5740 // If the class reference currently in `temp` is not null, jump
5741 // to the `compare_classes` label to compare it with the checked
5742 // class.
5743 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5744 // Otherwise, jump to the slow path to throw the exception.
5745 //
5746 // But before, move back the object's class into `temp` before
5747 // going into the slow path, as it has been overwritten in the
5748 // meantime.
5749 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005750 GenerateReferenceLoadTwoRegisters(
5751 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005752 __ b(type_check_slow_path->GetEntryLabel());
5753
5754 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005755 __ cmp(temp, ShifterOperand(cls));
5756 __ b(&loop, NE);
5757 break;
5758 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005759
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005760 case TypeCheckKind::kClassHierarchyCheck: {
5761 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005762 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005763 __ Bind(&loop);
5764 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005765 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005766
Roland Levillain3b359c72015-11-17 19:35:12 +00005767 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005768 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005769
5770 // If the class reference currently in `temp` is not null, jump
5771 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005772 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005773 // Otherwise, jump to the slow path to throw the exception.
5774 //
5775 // But before, move back the object's class into `temp` before
5776 // going into the slow path, as it has been overwritten in the
5777 // meantime.
5778 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005779 GenerateReferenceLoadTwoRegisters(
5780 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005781 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005782 break;
5783 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005784
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005785 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005786 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005787 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005788 __ cmp(temp, ShifterOperand(cls));
5789 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005790
5791 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005792 // /* HeapReference<Class> */ temp = temp->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005793 GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005794
5795 // If the component type is not null (i.e. the object is indeed
5796 // an array), jump to label `check_non_primitive_component_type`
5797 // to further check that this component type is not a primitive
5798 // type.
5799 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5800 // Otherwise, jump to the slow path to throw the exception.
5801 //
5802 // But before, move back the object's class into `temp` before
5803 // going into the slow path, as it has been overwritten in the
5804 // meantime.
5805 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005806 GenerateReferenceLoadTwoRegisters(
5807 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005808 __ b(type_check_slow_path->GetEntryLabel());
5809
5810 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005811 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005812 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5813 __ CompareAndBranchIfZero(temp, &done);
5814 // Same comment as above regarding `temp` and the slow path.
5815 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005816 GenerateReferenceLoadTwoRegisters(
5817 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005818 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005819 break;
5820 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005821
Calin Juravle98893e12015-10-02 21:05:03 +01005822 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005823 case TypeCheckKind::kInterfaceCheck:
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005824 // We always go into the type check slow path for the unresolved
5825 // and interface check cases.
Roland Levillain3b359c72015-11-17 19:35:12 +00005826 //
5827 // We cannot directly call the CheckCast runtime entry point
5828 // without resorting to a type checking slow path here (i.e. by
5829 // calling InvokeRuntime directly), as it would require to
5830 // assign fixed registers for the inputs of this HInstanceOf
5831 // instruction (following the runtime calling convention), which
5832 // might be cluttered by the potential first read barrier
5833 // emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005834 //
5835 // TODO: Introduce a new runtime entry point taking the object
5836 // to test (instead of its class) as argument, and let it deal
5837 // with the read barrier issues. This will let us refactor this
5838 // case of the `switch` code as it was previously (with a direct
5839 // call to the runtime not using a type checking slow path).
5840 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005841 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005842 break;
5843 }
5844 __ Bind(&done);
5845
Roland Levillain3b359c72015-11-17 19:35:12 +00005846 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005847}
5848
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005849void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5850 LocationSummary* locations =
5851 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5852 InvokeRuntimeCallingConvention calling_convention;
5853 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5854}
5855
5856void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5857 codegen_->InvokeRuntime(instruction->IsEnter()
5858 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5859 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005860 instruction->GetDexPc(),
5861 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005862 if (instruction->IsEnter()) {
5863 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5864 } else {
5865 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5866 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005867}
5868
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005869void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5870void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5871void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005872
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005873void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005874 LocationSummary* locations =
5875 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5876 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5877 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005878 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005879 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005880 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005881 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005882}
5883
5884void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5885 HandleBitwiseOperation(instruction);
5886}
5887
5888void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5889 HandleBitwiseOperation(instruction);
5890}
5891
5892void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5893 HandleBitwiseOperation(instruction);
5894}
5895
Artem Serov7fc63502016-02-09 17:15:29 +00005896
5897void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5898 LocationSummary* locations =
5899 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5900 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5901 || instruction->GetResultType() == Primitive::kPrimLong);
5902
5903 locations->SetInAt(0, Location::RequiresRegister());
5904 locations->SetInAt(1, Location::RequiresRegister());
5905 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5906}
5907
5908void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5909 LocationSummary* locations = instruction->GetLocations();
5910 Location first = locations->InAt(0);
5911 Location second = locations->InAt(1);
5912 Location out = locations->Out();
5913
5914 if (instruction->GetResultType() == Primitive::kPrimInt) {
5915 Register first_reg = first.AsRegister<Register>();
5916 ShifterOperand second_reg(second.AsRegister<Register>());
5917 Register out_reg = out.AsRegister<Register>();
5918
5919 switch (instruction->GetOpKind()) {
5920 case HInstruction::kAnd:
5921 __ bic(out_reg, first_reg, second_reg);
5922 break;
5923 case HInstruction::kOr:
5924 __ orn(out_reg, first_reg, second_reg);
5925 break;
5926 // There is no EON on arm.
5927 case HInstruction::kXor:
5928 default:
5929 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5930 UNREACHABLE();
5931 }
5932 return;
5933
5934 } else {
5935 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5936 Register first_low = first.AsRegisterPairLow<Register>();
5937 Register first_high = first.AsRegisterPairHigh<Register>();
5938 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5939 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5940 Register out_low = out.AsRegisterPairLow<Register>();
5941 Register out_high = out.AsRegisterPairHigh<Register>();
5942
5943 switch (instruction->GetOpKind()) {
5944 case HInstruction::kAnd:
5945 __ bic(out_low, first_low, second_low);
5946 __ bic(out_high, first_high, second_high);
5947 break;
5948 case HInstruction::kOr:
5949 __ orn(out_low, first_low, second_low);
5950 __ orn(out_high, first_high, second_high);
5951 break;
5952 // There is no EON on arm.
5953 case HInstruction::kXor:
5954 default:
5955 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5956 UNREACHABLE();
5957 }
5958 }
5959}
5960
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005961void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5962 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5963 if (value == 0xffffffffu) {
5964 if (out != first) {
5965 __ mov(out, ShifterOperand(first));
5966 }
5967 return;
5968 }
5969 if (value == 0u) {
5970 __ mov(out, ShifterOperand(0));
5971 return;
5972 }
5973 ShifterOperand so;
5974 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5975 __ and_(out, first, so);
5976 } else {
5977 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5978 __ bic(out, first, ShifterOperand(~value));
5979 }
5980}
5981
5982void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5983 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5984 if (value == 0u) {
5985 if (out != first) {
5986 __ mov(out, ShifterOperand(first));
5987 }
5988 return;
5989 }
5990 if (value == 0xffffffffu) {
5991 __ mvn(out, ShifterOperand(0));
5992 return;
5993 }
5994 ShifterOperand so;
5995 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5996 __ orr(out, first, so);
5997 } else {
5998 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5999 __ orn(out, first, ShifterOperand(~value));
6000 }
6001}
6002
6003void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6004 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6005 if (value == 0u) {
6006 if (out != first) {
6007 __ mov(out, ShifterOperand(first));
6008 }
6009 return;
6010 }
6011 __ eor(out, first, ShifterOperand(value));
6012}
6013
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006014void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6015 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006016 Location first = locations->InAt(0);
6017 Location second = locations->InAt(1);
6018 Location out = locations->Out();
6019
6020 if (second.IsConstant()) {
6021 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6022 uint32_t value_low = Low32Bits(value);
6023 if (instruction->GetResultType() == Primitive::kPrimInt) {
6024 Register first_reg = first.AsRegister<Register>();
6025 Register out_reg = out.AsRegister<Register>();
6026 if (instruction->IsAnd()) {
6027 GenerateAndConst(out_reg, first_reg, value_low);
6028 } else if (instruction->IsOr()) {
6029 GenerateOrrConst(out_reg, first_reg, value_low);
6030 } else {
6031 DCHECK(instruction->IsXor());
6032 GenerateEorConst(out_reg, first_reg, value_low);
6033 }
6034 } else {
6035 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6036 uint32_t value_high = High32Bits(value);
6037 Register first_low = first.AsRegisterPairLow<Register>();
6038 Register first_high = first.AsRegisterPairHigh<Register>();
6039 Register out_low = out.AsRegisterPairLow<Register>();
6040 Register out_high = out.AsRegisterPairHigh<Register>();
6041 if (instruction->IsAnd()) {
6042 GenerateAndConst(out_low, first_low, value_low);
6043 GenerateAndConst(out_high, first_high, value_high);
6044 } else if (instruction->IsOr()) {
6045 GenerateOrrConst(out_low, first_low, value_low);
6046 GenerateOrrConst(out_high, first_high, value_high);
6047 } else {
6048 DCHECK(instruction->IsXor());
6049 GenerateEorConst(out_low, first_low, value_low);
6050 GenerateEorConst(out_high, first_high, value_high);
6051 }
6052 }
6053 return;
6054 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006055
6056 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006057 Register first_reg = first.AsRegister<Register>();
6058 ShifterOperand second_reg(second.AsRegister<Register>());
6059 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006060 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006061 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006062 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006063 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006064 } else {
6065 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006066 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006067 }
6068 } else {
6069 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006070 Register first_low = first.AsRegisterPairLow<Register>();
6071 Register first_high = first.AsRegisterPairHigh<Register>();
6072 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6073 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6074 Register out_low = out.AsRegisterPairLow<Register>();
6075 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006076 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006077 __ and_(out_low, first_low, second_low);
6078 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006079 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006080 __ orr(out_low, first_low, second_low);
6081 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006082 } else {
6083 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006084 __ eor(out_low, first_low, second_low);
6085 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006086 }
6087 }
6088}
6089
Roland Levillainc9285912015-12-18 10:38:42 +00006090void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
6091 Location out,
6092 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006093 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006094 Register out_reg = out.AsRegister<Register>();
6095 if (kEmitCompilerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006096 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006097 if (kUseBakerReadBarrier) {
6098 // Load with fast path based Baker's read barrier.
6099 // /* HeapReference<Object> */ out = *(out + offset)
6100 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006101 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006102 } else {
6103 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006104 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006105 // in the following move operation, as we will need it for the
6106 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006107 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006108 // /* HeapReference<Object> */ out = *(out + offset)
6109 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006110 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006111 }
6112 } else {
6113 // Plain load with no read barrier.
6114 // /* HeapReference<Object> */ out = *(out + offset)
6115 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6116 __ MaybeUnpoisonHeapReference(out_reg);
6117 }
6118}
6119
6120void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6121 Location out,
6122 Location obj,
6123 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006124 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006125 Register out_reg = out.AsRegister<Register>();
6126 Register obj_reg = obj.AsRegister<Register>();
6127 if (kEmitCompilerReadBarrier) {
6128 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006129 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006130 // Load with fast path based Baker's read barrier.
6131 // /* HeapReference<Object> */ out = *(obj + offset)
6132 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006133 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006134 } else {
6135 // Load with slow path based read barrier.
6136 // /* HeapReference<Object> */ out = *(obj + offset)
6137 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6138 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6139 }
6140 } else {
6141 // Plain load with no read barrier.
6142 // /* HeapReference<Object> */ out = *(obj + offset)
6143 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6144 __ MaybeUnpoisonHeapReference(out_reg);
6145 }
6146}
6147
6148void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6149 Location root,
6150 Register obj,
6151 uint32_t offset) {
6152 Register root_reg = root.AsRegister<Register>();
6153 if (kEmitCompilerReadBarrier) {
6154 if (kUseBakerReadBarrier) {
6155 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6156 // Baker's read barrier are used:
6157 //
6158 // root = obj.field;
6159 // if (Thread::Current()->GetIsGcMarking()) {
6160 // root = ReadBarrier::Mark(root)
6161 // }
6162
6163 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6164 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6165 static_assert(
6166 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6167 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6168 "have different sizes.");
6169 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6170 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6171 "have different sizes.");
6172
6173 // Slow path used to mark the GC root `root`.
6174 SlowPathCode* slow_path =
6175 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
6176 codegen_->AddSlowPath(slow_path);
6177
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006178 // IP = Thread::Current()->GetIsGcMarking()
Roland Levillainc9285912015-12-18 10:38:42 +00006179 __ LoadFromOffset(
6180 kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6181 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6182 __ Bind(slow_path->GetExitLabel());
6183 } else {
6184 // GC root loaded through a slow path for read barriers other
6185 // than Baker's.
6186 // /* GcRoot<mirror::Object>* */ root = obj + offset
6187 __ AddConstant(root_reg, obj, offset);
6188 // /* mirror::Object* */ root = root->Read()
6189 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6190 }
6191 } else {
6192 // Plain GC root load with no read barrier.
6193 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6194 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6195 // Note that GC roots are not affected by heap poisoning, thus we
6196 // do not have to unpoison `root_reg` here.
6197 }
6198}
6199
6200void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6201 Location ref,
6202 Register obj,
6203 uint32_t offset,
6204 Location temp,
6205 bool needs_null_check) {
6206 DCHECK(kEmitCompilerReadBarrier);
6207 DCHECK(kUseBakerReadBarrier);
6208
6209 // /* HeapReference<Object> */ ref = *(obj + offset)
6210 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01006211 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00006212 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006213 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006214}
6215
6216void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6217 Location ref,
6218 Register obj,
6219 uint32_t data_offset,
6220 Location index,
6221 Location temp,
6222 bool needs_null_check) {
6223 DCHECK(kEmitCompilerReadBarrier);
6224 DCHECK(kUseBakerReadBarrier);
6225
Roland Levillainbfea3352016-06-23 13:48:47 +01006226 static_assert(
6227 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6228 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006229 // /* HeapReference<Object> */ ref =
6230 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01006231 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00006232 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006233 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006234}
6235
6236void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6237 Location ref,
6238 Register obj,
6239 uint32_t offset,
6240 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01006241 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00006242 Location temp,
6243 bool needs_null_check) {
6244 DCHECK(kEmitCompilerReadBarrier);
6245 DCHECK(kUseBakerReadBarrier);
6246
6247 // In slow path based read barriers, the read barrier call is
6248 // inserted after the original load. However, in fast path based
6249 // Baker's read barriers, we need to perform the load of
6250 // mirror::Object::monitor_ *before* the original reference load.
6251 // This load-load ordering is required by the read barrier.
6252 // The fast path/slow path (for Baker's algorithm) should look like:
6253 //
6254 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6255 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6256 // HeapReference<Object> ref = *src; // Original reference load.
6257 // bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6258 // if (is_gray) {
6259 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6260 // }
6261 //
6262 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006263 // slightly more complex as it performs additional checks that we do
6264 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00006265
6266 Register ref_reg = ref.AsRegister<Register>();
6267 Register temp_reg = temp.AsRegister<Register>();
6268 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6269
6270 // /* int32_t */ monitor = obj->monitor_
6271 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6272 if (needs_null_check) {
6273 MaybeRecordImplicitNullCheck(instruction);
6274 }
6275 // /* LockWord */ lock_word = LockWord(monitor)
6276 static_assert(sizeof(LockWord) == sizeof(int32_t),
6277 "art::LockWord and int32_t have different sizes.");
6278 // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
6279 __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
6280 __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6281 static_assert(
6282 LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
6283 "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
6284
6285 // Introduce a dependency on the high bits of rb_state, which shall
6286 // be all zeroes, to prevent load-load reordering, and without using
6287 // a memory barrier (which would be more expensive).
6288 // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
6289 __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6290 // obj is unchanged by this operation, but its value now depends on
6291 // IP, which depends on temp_reg.
6292 __ add(obj, obj, ShifterOperand(IP));
6293
6294 // The actual reference load.
6295 if (index.IsValid()) {
Roland Levillainbfea3352016-06-23 13:48:47 +01006296 // Load types involving an "index": ArrayGet and
6297 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
6298 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00006299 if (index.IsConstant()) {
6300 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01006301 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006302 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6303 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01006304 // Handle the special case of the
6305 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use
6306 // a register pair as index ("long offset"), of which only the low
6307 // part contains data.
6308 Register index_reg = index.IsRegisterPair()
6309 ? index.AsRegisterPairLow<Register>()
6310 : index.AsRegister<Register>();
6311 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00006312 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6313 }
6314 } else {
6315 // /* HeapReference<Object> */ ref = *(obj + offset)
6316 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6317 }
6318
6319 // Object* ref = ref_addr->AsMirrorPtr()
6320 __ MaybeUnpoisonHeapReference(ref_reg);
6321
6322 // Slow path used to mark the object `ref` when it is gray.
6323 SlowPathCode* slow_path =
6324 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
6325 AddSlowPath(slow_path);
6326
6327 // if (rb_state == ReadBarrier::gray_ptr_)
6328 // ref = ReadBarrier::Mark(ref);
6329 __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
6330 __ b(slow_path->GetEntryLabel(), EQ);
6331 __ Bind(slow_path->GetExitLabel());
6332}
6333
6334void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6335 Location out,
6336 Location ref,
6337 Location obj,
6338 uint32_t offset,
6339 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006340 DCHECK(kEmitCompilerReadBarrier);
6341
Roland Levillainc9285912015-12-18 10:38:42 +00006342 // Insert a slow path based read barrier *after* the reference load.
6343 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006344 // If heap poisoning is enabled, the unpoisoning of the loaded
6345 // reference will be carried out by the runtime within the slow
6346 // path.
6347 //
6348 // Note that `ref` currently does not get unpoisoned (when heap
6349 // poisoning is enabled), which is alright as the `ref` argument is
6350 // not used by the artReadBarrierSlow entry point.
6351 //
6352 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6353 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6354 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6355 AddSlowPath(slow_path);
6356
Roland Levillain3b359c72015-11-17 19:35:12 +00006357 __ b(slow_path->GetEntryLabel());
6358 __ Bind(slow_path->GetExitLabel());
6359}
6360
Roland Levillainc9285912015-12-18 10:38:42 +00006361void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6362 Location out,
6363 Location ref,
6364 Location obj,
6365 uint32_t offset,
6366 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006367 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00006368 // Baker's read barriers shall be handled by the fast path
6369 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6370 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006371 // If heap poisoning is enabled, unpoisoning will be taken care of
6372 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00006373 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00006374 } else if (kPoisonHeapReferences) {
6375 __ UnpoisonHeapReference(out.AsRegister<Register>());
6376 }
6377}
6378
Roland Levillainc9285912015-12-18 10:38:42 +00006379void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6380 Location out,
6381 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006382 DCHECK(kEmitCompilerReadBarrier);
6383
Roland Levillainc9285912015-12-18 10:38:42 +00006384 // Insert a slow path based read barrier *after* the GC root load.
6385 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006386 // Note that GC roots are not affected by heap poisoning, so we do
6387 // not need to do anything special for this here.
6388 SlowPathCode* slow_path =
6389 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6390 AddSlowPath(slow_path);
6391
Roland Levillain3b359c72015-11-17 19:35:12 +00006392 __ b(slow_path->GetEntryLabel());
6393 __ Bind(slow_path->GetExitLabel());
6394}
6395
Vladimir Markodc151b22015-10-15 18:02:30 +01006396HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6397 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6398 MethodReference target_method) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006399 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6400 // We disable pc-relative load when there is an irreducible loop, as the optimization
6401 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006402 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6403 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006404 if (GetGraph()->HasIrreducibleLoops() &&
6405 (dispatch_info.method_load_kind ==
6406 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6407 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6408 }
6409
6410 if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
Vladimir Markodc151b22015-10-15 18:02:30 +01006411 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6412 if (&outer_dex_file != target_method.dex_file) {
6413 // Calls across dex files are more likely to exceed the available BL range,
6414 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6415 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6416 (desired_dispatch_info.method_load_kind ==
6417 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6418 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6419 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6420 return HInvokeStaticOrDirect::DispatchInfo {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006421 dispatch_info.method_load_kind,
Vladimir Markodc151b22015-10-15 18:02:30 +01006422 code_ptr_location,
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006423 dispatch_info.method_load_data,
Vladimir Markodc151b22015-10-15 18:02:30 +01006424 0u
6425 };
6426 }
6427 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006428 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01006429}
6430
Vladimir Markob4536b72015-11-24 13:45:23 +00006431Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6432 Register temp) {
6433 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6434 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6435 if (!invoke->GetLocations()->Intrinsified()) {
6436 return location.AsRegister<Register>();
6437 }
6438 // For intrinsics we allow any location, so it may be on the stack.
6439 if (!location.IsRegister()) {
6440 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6441 return temp;
6442 }
6443 // For register locations, check if the register was saved. If so, get it from the stack.
6444 // Note: There is a chance that the register was saved but not overwritten, so we could
6445 // save one load. However, since this is just an intrinsic slow path we prefer this
6446 // simple and more robust approach rather that trying to determine if that's the case.
6447 SlowPathCode* slow_path = GetCurrentSlowPath();
6448 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6449 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6450 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6451 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6452 return temp;
6453 }
6454 return location.AsRegister<Register>();
6455}
6456
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006457void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006458 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006459 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006460 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6461 // LR = code address from literal pool with link-time patch.
6462 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006463 break;
6464 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6465 // LR = invoke->GetDirectCodePtr();
6466 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006467 break;
6468 default:
6469 break;
6470 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006471
Vladimir Marko58155012015-08-19 12:49:41 +00006472 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6473 switch (invoke->GetMethodLoadKind()) {
6474 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6475 // temp = thread->string_init_entrypoint
6476 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6477 break;
6478 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006479 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006480 break;
6481 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6482 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6483 break;
6484 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6485 __ LoadLiteral(temp.AsRegister<Register>(),
6486 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6487 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006488 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6489 HArmDexCacheArraysBase* base =
6490 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6491 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6492 temp.AsRegister<Register>());
6493 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6494 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6495 break;
6496 }
Vladimir Marko58155012015-08-19 12:49:41 +00006497 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006498 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006499 Register method_reg;
6500 Register reg = temp.AsRegister<Register>();
6501 if (current_method.IsRegister()) {
6502 method_reg = current_method.AsRegister<Register>();
6503 } else {
6504 DCHECK(invoke->GetLocations()->Intrinsified());
6505 DCHECK(!current_method.IsValid());
6506 method_reg = reg;
6507 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6508 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006509 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6510 __ LoadFromOffset(kLoadWord,
6511 reg,
6512 method_reg,
6513 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01006514 // temp = temp[index_in_cache];
6515 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6516 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00006517 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6518 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006519 }
Vladimir Marko58155012015-08-19 12:49:41 +00006520 }
6521
6522 switch (invoke->GetCodePtrLocation()) {
6523 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6524 __ bl(GetFrameEntryLabel());
6525 break;
6526 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006527 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006528 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006529 // Arbitrarily branch to the BL itself, override at link time.
6530 __ bl(&relative_call_patches_.back().label);
6531 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006532 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6533 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6534 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006535 // LR()
6536 __ blx(LR);
6537 break;
6538 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6539 // LR = callee_method->entry_point_from_quick_compiled_code_
6540 __ LoadFromOffset(
6541 kLoadWord, LR, callee_method.AsRegister<Register>(),
6542 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6543 // LR()
6544 __ blx(LR);
6545 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006546 }
6547
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006548 DCHECK(!IsLeafMethod());
6549}
6550
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006551void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6552 Register temp = temp_location.AsRegister<Register>();
6553 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6554 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006555
6556 // Use the calling convention instead of the location of the receiver, as
6557 // intrinsics may have put the receiver in a different register. In the intrinsics
6558 // slow path, the arguments have been moved to the right place, so here we are
6559 // guaranteed that the receiver is the first register of the calling convention.
6560 InvokeDexCallingConvention calling_convention;
6561 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006562 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006563 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006564 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006565 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006566 // Instead of simply (possibly) unpoisoning `temp` here, we should
6567 // emit a read barrier for the previous class reference load.
6568 // However this is not required in practice, as this is an
6569 // intermediate/temporary reference and because the current
6570 // concurrent copying collector keeps the from-space memory
6571 // intact/accessible until the end of the marking phase (the
6572 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006573 __ MaybeUnpoisonHeapReference(temp);
6574 // temp = temp->GetMethodAt(method_offset);
6575 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6576 kArmWordSize).Int32Value();
6577 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6578 // LR = temp->GetEntryPoint();
6579 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6580 // LR();
6581 __ blx(LR);
6582}
6583
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006584CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6585 const DexFile& dex_file, uint32_t string_index) {
6586 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6587}
6588
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006589CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
6590 const DexFile& dex_file, uint32_t type_index) {
6591 return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
6592}
6593
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006594CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6595 const DexFile& dex_file, uint32_t element_offset) {
6596 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6597}
6598
6599CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6600 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6601 patches->emplace_back(dex_file, offset_or_index);
6602 return &patches->back();
6603}
6604
6605Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6606 uint32_t string_index) {
6607 return boot_image_string_patches_.GetOrCreate(
6608 StringReference(&dex_file, string_index),
6609 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6610}
6611
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006612Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
6613 uint32_t type_index) {
6614 return boot_image_type_patches_.GetOrCreate(
6615 TypeReference(&dex_file, type_index),
6616 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6617}
6618
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006619Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6620 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6621 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6622 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6623}
6624
6625Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6626 return DeduplicateUint32Literal(address, &uint32_literals_);
6627}
6628
Vladimir Marko58155012015-08-19 12:49:41 +00006629void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6630 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006631 size_t size =
6632 method_patches_.size() +
6633 call_patches_.size() +
6634 relative_call_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006635 /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6636 boot_image_string_patches_.size() +
6637 /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006638 boot_image_type_patches_.size() +
6639 /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006640 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006641 linker_patches->reserve(size);
6642 for (const auto& entry : method_patches_) {
6643 const MethodReference& target_method = entry.first;
6644 Literal* literal = entry.second;
6645 DCHECK(literal->GetLabel()->IsBound());
6646 uint32_t literal_offset = literal->GetLabel()->Position();
6647 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6648 target_method.dex_file,
6649 target_method.dex_method_index));
6650 }
6651 for (const auto& entry : call_patches_) {
6652 const MethodReference& target_method = entry.first;
6653 Literal* literal = entry.second;
6654 DCHECK(literal->GetLabel()->IsBound());
6655 uint32_t literal_offset = literal->GetLabel()->Position();
6656 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6657 target_method.dex_file,
6658 target_method.dex_method_index));
6659 }
6660 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6661 uint32_t literal_offset = info.label.Position();
6662 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6663 info.target_method.dex_file,
6664 info.target_method.dex_method_index));
6665 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006666 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6667 const DexFile& dex_file = info.target_dex_file;
6668 size_t base_element_offset = info.offset_or_index;
6669 DCHECK(info.add_pc_label.IsBound());
6670 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006671 // Add MOVW patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006672 DCHECK(info.movw_label.IsBound());
6673 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006674 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6675 &dex_file,
6676 add_pc_offset,
6677 base_element_offset));
6678 // Add MOVT patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006679 DCHECK(info.movt_label.IsBound());
6680 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006681 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6682 &dex_file,
6683 add_pc_offset,
6684 base_element_offset));
6685 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006686 for (const auto& entry : boot_image_string_patches_) {
6687 const StringReference& target_string = entry.first;
6688 Literal* literal = entry.second;
6689 DCHECK(literal->GetLabel()->IsBound());
6690 uint32_t literal_offset = literal->GetLabel()->Position();
6691 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6692 target_string.dex_file,
6693 target_string.string_index));
6694 }
6695 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6696 const DexFile& dex_file = info.target_dex_file;
6697 uint32_t string_index = info.offset_or_index;
6698 DCHECK(info.add_pc_label.IsBound());
6699 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6700 // Add MOVW patch.
6701 DCHECK(info.movw_label.IsBound());
6702 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6703 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6704 &dex_file,
6705 add_pc_offset,
6706 string_index));
6707 // Add MOVT patch.
6708 DCHECK(info.movt_label.IsBound());
6709 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6710 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6711 &dex_file,
6712 add_pc_offset,
6713 string_index));
6714 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006715 for (const auto& entry : boot_image_type_patches_) {
6716 const TypeReference& target_type = entry.first;
6717 Literal* literal = entry.second;
6718 DCHECK(literal->GetLabel()->IsBound());
6719 uint32_t literal_offset = literal->GetLabel()->Position();
6720 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
6721 target_type.dex_file,
6722 target_type.type_index));
6723 }
6724 for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
6725 const DexFile& dex_file = info.target_dex_file;
6726 uint32_t type_index = info.offset_or_index;
6727 DCHECK(info.add_pc_label.IsBound());
6728 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6729 // Add MOVW patch.
6730 DCHECK(info.movw_label.IsBound());
6731 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6732 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset,
6733 &dex_file,
6734 add_pc_offset,
6735 type_index));
6736 // Add MOVT patch.
6737 DCHECK(info.movt_label.IsBound());
6738 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6739 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset,
6740 &dex_file,
6741 add_pc_offset,
6742 type_index));
6743 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006744 for (const auto& entry : boot_image_address_patches_) {
6745 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6746 Literal* literal = entry.second;
6747 DCHECK(literal->GetLabel()->IsBound());
6748 uint32_t literal_offset = literal->GetLabel()->Position();
6749 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6750 }
6751}
6752
6753Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6754 return map->GetOrCreate(
6755 value,
6756 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00006757}
6758
6759Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6760 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006761 return map->GetOrCreate(
6762 target_method,
6763 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00006764}
6765
6766Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6767 return DeduplicateMethodLiteral(target_method, &method_patches_);
6768}
6769
6770Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6771 return DeduplicateMethodLiteral(target_method, &call_patches_);
6772}
6773
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03006774void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6775 LocationSummary* locations =
6776 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6777 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6778 Location::RequiresRegister());
6779 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6780 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6781 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6782}
6783
6784void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6785 LocationSummary* locations = instr->GetLocations();
6786 Register res = locations->Out().AsRegister<Register>();
6787 Register accumulator =
6788 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6789 Register mul_left =
6790 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6791 Register mul_right =
6792 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6793
6794 if (instr->GetOpKind() == HInstruction::kAdd) {
6795 __ mla(res, mul_left, mul_right, accumulator);
6796 } else {
6797 __ mls(res, mul_left, mul_right, accumulator);
6798 }
6799}
6800
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006801void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006802 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006803 LOG(FATAL) << "Unreachable";
6804}
6805
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006806void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006807 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006808 LOG(FATAL) << "Unreachable";
6809}
6810
Mark Mendellfe57faa2015-09-18 09:26:15 -04006811// Simple implementation of packed switch - generate cascaded compare/jumps.
6812void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6813 LocationSummary* locations =
6814 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6815 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006816 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006817 codegen_->GetAssembler()->IsThumb()) {
6818 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6819 if (switch_instr->GetStartValue() != 0) {
6820 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6821 }
6822 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006823}
6824
6825void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6826 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006827 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006828 LocationSummary* locations = switch_instr->GetLocations();
6829 Register value_reg = locations->InAt(0).AsRegister<Register>();
6830 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6831
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006832 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006833 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006834 Register temp_reg = IP;
6835 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6836 // the immediate, because IP is used as the destination register. For the other
6837 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6838 // and they can be encoded in the instruction without making use of IP register.
6839 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6840
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006841 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006842 // Jump to successors[0] if value == lower_bound.
6843 __ b(codegen_->GetLabelOf(successors[0]), EQ);
6844 int32_t last_index = 0;
6845 for (; num_entries - last_index > 2; last_index += 2) {
6846 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6847 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6848 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6849 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6850 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6851 }
6852 if (num_entries - last_index == 2) {
6853 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00006854 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006855 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006856 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006857
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006858 // And the default for any other value.
6859 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6860 __ b(codegen_->GetLabelOf(default_block));
6861 }
6862 } else {
6863 // Create a table lookup.
6864 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6865
6866 // Materialize a pointer to the switch table
6867 std::vector<Label*> labels(num_entries);
6868 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6869 for (uint32_t i = 0; i < num_entries; i++) {
6870 labels[i] = codegen_->GetLabelOf(successors[i]);
6871 }
6872 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6873
6874 // Remove the bias.
6875 Register key_reg;
6876 if (lower_bound != 0) {
6877 key_reg = locations->GetTemp(1).AsRegister<Register>();
6878 __ AddConstant(key_reg, value_reg, -lower_bound);
6879 } else {
6880 key_reg = value_reg;
6881 }
6882
6883 // Check whether the value is in the table, jump to default block if not.
6884 __ CmpConstant(key_reg, num_entries - 1);
6885 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6886
6887 // Load the displacement from the table.
6888 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6889
6890 // Dispatch is a direct add to the PC (for Thumb2).
6891 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006892 }
6893}
6894
Vladimir Markob4536b72015-11-24 13:45:23 +00006895void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6896 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6897 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00006898}
6899
6900void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6901 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006902 CodeGeneratorARM::PcRelativePatchInfo* labels =
6903 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00006904 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006905 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006906 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006907 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006908 __ BindTrackedLabel(&labels->add_pc_label);
6909 __ add(base_reg, base_reg, ShifterOperand(PC));
6910}
6911
Andreas Gampe85b62f22015-09-09 13:15:38 -07006912void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6913 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00006914 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07006915 return;
6916 }
6917
6918 DCHECK_NE(type, Primitive::kPrimVoid);
6919
6920 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6921 if (return_loc.Equals(trg)) {
6922 return;
6923 }
6924
6925 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6926 // with the last branch.
6927 if (type == Primitive::kPrimLong) {
6928 HParallelMove parallel_move(GetGraph()->GetArena());
6929 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6930 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6931 GetMoveResolver()->EmitNativeCode(&parallel_move);
6932 } else if (type == Primitive::kPrimDouble) {
6933 HParallelMove parallel_move(GetGraph()->GetArena());
6934 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6935 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6936 GetMoveResolver()->EmitNativeCode(&parallel_move);
6937 } else {
6938 // Let the parallel move resolver take care of all of this.
6939 HParallelMove parallel_move(GetGraph()->GetArena());
6940 parallel_move.AddMove(return_loc, trg, type, nullptr);
6941 GetMoveResolver()->EmitNativeCode(&parallel_move);
6942 }
6943}
6944
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006945void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
6946 LocationSummary* locations =
6947 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6948 locations->SetInAt(0, Location::RequiresRegister());
6949 locations->SetOut(Location::RequiresRegister());
6950}
6951
6952void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
6953 LocationSummary* locations = instruction->GetLocations();
6954 uint32_t method_offset = 0;
Vladimir Markoa1de9182016-02-25 11:37:38 +00006955 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006956 method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6957 instruction->GetIndex(), kArmPointerSize).SizeValue();
6958 } else {
Nicolas Geoffray88f288e2016-06-29 08:17:52 +00006959 method_offset = mirror::Class::EmbeddedImTableEntryOffset(
6960 instruction->GetIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006961 }
6962 __ LoadFromOffset(kLoadWord,
6963 locations->Out().AsRegister<Register>(),
6964 locations->InAt(0).AsRegister<Register>(),
6965 method_offset);
6966}
6967
Roland Levillain4d027112015-07-01 15:41:14 +01006968#undef __
6969#undef QUICK_ENTRY_POINT
6970
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006971} // namespace arm
6972} // namespace art