blob: c105940f284a950ee93773986c505df4f0b090a0 [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
Andreas Gampe542451c2016-07-26 09:02:02 -070064#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, 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 Geoffray19a19cf2014-10-22 16:07:05 +0100122 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000123 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000124 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100125 if (successor_ == nullptr) {
126 __ b(GetReturnLabel());
127 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100128 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100129 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000130 }
131
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100132 Label* GetReturnLabel() {
133 DCHECK(successor_ == nullptr);
134 return &return_label_;
135 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000136
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100137 HBasicBlock* GetSuccessor() const {
138 return successor_;
139 }
140
Alexandre Rames9931f312015-06-19 14:47:01 +0100141 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
142
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000143 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100144 // If not null, the block to branch to after the suspend check.
145 HBasicBlock* const successor_;
146
147 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 Label return_label_;
149
150 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
151};
152
Andreas Gampe85b62f22015-09-09 13:15:38 -0700153class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100154 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100155 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000156 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100157
Alexandre Rames67555f72014-11-18 10:55:16 +0000158 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100159 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100160 LocationSummary* locations = instruction_->GetLocations();
161
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100162 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000163 if (instruction_->CanThrowIntoCatchBlock()) {
164 // Live registers will be restored in the catch block if caught.
165 SaveLiveRegisters(codegen, instruction_->GetLocations());
166 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000167 // We're moving two locations to locations that could overlap, so we need a parallel
168 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100169 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000170 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100171 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000172 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100173 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100174 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100175 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
176 Primitive::kPrimInt);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100177 uint32_t entry_point_offset = instruction_->AsBoundsCheck()->IsStringCharAt()
178 ? QUICK_ENTRY_POINT(pThrowStringBounds)
179 : QUICK_ENTRY_POINT(pThrowArrayBounds);
180 arm_codegen->InvokeRuntime(entry_point_offset, instruction_, instruction_->GetDexPc(), this);
181 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000182 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183 }
184
Alexandre Rames8158f282015-08-07 10:26:17 +0100185 bool IsFatal() const OVERRIDE { return true; }
186
Alexandre Rames9931f312015-06-19 14:47:01 +0100187 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
188
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100190 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
191};
192
Andreas Gampe85b62f22015-09-09 13:15:38 -0700193class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100194 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000195 LoadClassSlowPathARM(HLoadClass* cls,
196 HInstruction* at,
197 uint32_t dex_pc,
198 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000199 : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000200 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
201 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100202
Alexandre Rames67555f72014-11-18 10:55:16 +0000203 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204 LocationSummary* locations = at_->GetLocations();
205
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100206 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
207 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000208 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100210 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000212 int32_t entry_point_offset = do_clinit_
213 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
214 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000215 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000216 if (do_clinit_) {
217 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
218 } else {
219 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
220 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000221
222 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000223 Location out = locations->Out();
224 if (out.IsValid()) {
225 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
227 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000228 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100229 __ b(GetExitLabel());
230 }
231
Alexandre Rames9931f312015-06-19 14:47:01 +0100232 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
233
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100234 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000235 // The class this slow path will load.
236 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100237
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000238 // The instruction where this slow path is happening.
239 // (Might be the load class or an initialization check).
240 HInstruction* const at_;
241
242 // The dex PC of `at_`.
243 const uint32_t dex_pc_;
244
245 // Whether to initialize the class.
246 const bool do_clinit_;
247
248 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100249};
250
Andreas Gampe85b62f22015-09-09 13:15:38 -0700251class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000252 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000253 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000254
Alexandre Rames67555f72014-11-18 10:55:16 +0000255 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000256 LocationSummary* locations = instruction_->GetLocations();
257 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
258
259 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
260 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000261 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000262
263 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000264 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
265 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000266 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000267 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000268 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000269 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
270
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000271 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000272 __ b(GetExitLabel());
273 }
274
Alexandre Rames9931f312015-06-19 14:47:01 +0100275 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
276
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000277 private:
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000278 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
279};
280
Andreas Gampe85b62f22015-09-09 13:15:38 -0700281class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000282 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000283 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000284 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285
Alexandre Rames67555f72014-11-18 10:55:16 +0000286 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000287 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100288 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
289 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000290 DCHECK(instruction_->IsCheckCast()
291 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292
293 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
294 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000295
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000296 if (!is_fatal_) {
297 SaveLiveRegisters(codegen, locations);
298 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299
300 // We're moving two locations to locations that could overlap, so we need a parallel
301 // move resolver.
302 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000303 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100304 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000305 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100306 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100307 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100308 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
309 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000311 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100312 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
313 instruction_,
314 instruction_->GetDexPc(),
315 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000316 CheckEntrypointTypes<
Andreas Gampe67409972016-07-19 22:34:53 -0700317 kQuickInstanceofNonTrivial, size_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000318 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
319 } else {
320 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100321 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
322 instruction_,
323 instruction_->GetDexPc(),
324 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000325 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000326 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000327
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000328 if (!is_fatal_) {
329 RestoreLiveRegisters(codegen, locations);
330 __ b(GetExitLabel());
331 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000332 }
333
Alexandre Rames9931f312015-06-19 14:47:01 +0100334 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
335
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000336 bool IsFatal() const OVERRIDE { return is_fatal_; }
337
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000338 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000339 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340
341 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
342};
343
Andreas Gampe85b62f22015-09-09 13:15:38 -0700344class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700345 public:
Aart Bik42249c32016-01-07 15:33:50 -0800346 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000347 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700348
349 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800350 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700351 __ Bind(GetEntryLabel());
352 SaveLiveRegisters(codegen, instruction_->GetLocations());
Aart Bik42249c32016-01-07 15:33:50 -0800353 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
354 instruction_,
355 instruction_->GetDexPc(),
356 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000357 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700358 }
359
Alexandre Rames9931f312015-06-19 14:47:01 +0100360 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
361
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700362 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700363 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
364};
365
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100366class ArraySetSlowPathARM : public SlowPathCode {
367 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000368 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100369
370 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
371 LocationSummary* locations = instruction_->GetLocations();
372 __ Bind(GetEntryLabel());
373 SaveLiveRegisters(codegen, locations);
374
375 InvokeRuntimeCallingConvention calling_convention;
376 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
377 parallel_move.AddMove(
378 locations->InAt(0),
379 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
380 Primitive::kPrimNot,
381 nullptr);
382 parallel_move.AddMove(
383 locations->InAt(1),
384 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
385 Primitive::kPrimInt,
386 nullptr);
387 parallel_move.AddMove(
388 locations->InAt(2),
389 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
390 Primitive::kPrimNot,
391 nullptr);
392 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
393
394 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
395 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
396 instruction_,
397 instruction_->GetDexPc(),
398 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000399 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100400 RestoreLiveRegisters(codegen, locations);
401 __ b(GetExitLabel());
402 }
403
404 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
405
406 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100407 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
408};
409
Roland Levillainc9285912015-12-18 10:38:42 +0000410// Slow path marking an object during a read barrier.
411class ReadBarrierMarkSlowPathARM : public SlowPathCode {
412 public:
Roland Levillain02b75802016-07-13 11:54:35 +0100413 ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location obj)
414 : SlowPathCode(instruction), obj_(obj) {
Roland Levillainc9285912015-12-18 10:38:42 +0000415 DCHECK(kEmitCompilerReadBarrier);
416 }
417
418 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
419
420 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
421 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain02b75802016-07-13 11:54:35 +0100422 Register reg = obj_.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +0000423 DCHECK(locations->CanCall());
Roland Levillain02b75802016-07-13 11:54:35 +0100424 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg));
Roland Levillainc9285912015-12-18 10:38:42 +0000425 DCHECK(instruction_->IsInstanceFieldGet() ||
426 instruction_->IsStaticFieldGet() ||
427 instruction_->IsArrayGet() ||
428 instruction_->IsLoadClass() ||
429 instruction_->IsLoadString() ||
430 instruction_->IsInstanceOf() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100431 instruction_->IsCheckCast() ||
Roland Levillaindec8f632016-07-22 17:10:06 +0100432 (instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())
Roland Levillainc9285912015-12-18 10:38:42 +0000433 << "Unexpected instruction in read barrier marking slow path: "
434 << instruction_->DebugName();
435
436 __ Bind(GetEntryLabel());
Roland Levillain4359e612016-07-20 11:32:19 +0100437 // No need to save live registers; it's taken care of by the
438 // entrypoint. Also, there is no need to update the stack mask,
439 // as this runtime call will not trigger a garbage collection.
Roland Levillainc9285912015-12-18 10:38:42 +0000440 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Roland Levillain02b75802016-07-13 11:54:35 +0100441 DCHECK_NE(reg, SP);
442 DCHECK_NE(reg, LR);
443 DCHECK_NE(reg, PC);
444 DCHECK(0 <= reg && reg < kNumberOfCoreRegisters) << reg;
445 // "Compact" slow path, saving two moves.
446 //
447 // Instead of using the standard runtime calling convention (input
448 // and output in R0):
449 //
450 // R0 <- obj
451 // R0 <- ReadBarrierMark(R0)
452 // obj <- R0
453 //
454 // we just use rX (the register holding `obj`) as input and output
455 // of a dedicated entrypoint:
456 //
457 // rX <- ReadBarrierMarkRegX(rX)
458 //
459 int32_t entry_point_offset =
Andreas Gampe542451c2016-07-26 09:02:02 -0700460 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(reg);
Roland Levillaindec8f632016-07-22 17:10:06 +0100461 // This runtime call does not require a stack map.
462 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
Roland Levillainc9285912015-12-18 10:38:42 +0000463 __ b(GetExitLabel());
464 }
465
466 private:
Roland Levillainc9285912015-12-18 10:38:42 +0000467 const Location obj_;
468
469 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
470};
471
Roland Levillain3b359c72015-11-17 19:35:12 +0000472// Slow path generating a read barrier for a heap reference.
473class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
474 public:
475 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
476 Location out,
477 Location ref,
478 Location obj,
479 uint32_t offset,
480 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000481 : SlowPathCode(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000482 out_(out),
483 ref_(ref),
484 obj_(obj),
485 offset_(offset),
486 index_(index) {
487 DCHECK(kEmitCompilerReadBarrier);
488 // If `obj` is equal to `out` or `ref`, it means the initial object
489 // has been overwritten by (or after) the heap object reference load
490 // to be instrumented, e.g.:
491 //
492 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000493 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000494 //
495 // In that case, we have lost the information about the original
496 // object, and the emitted read barrier cannot work properly.
497 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
498 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
499 }
500
501 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
502 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
503 LocationSummary* locations = instruction_->GetLocations();
504 Register reg_out = out_.AsRegister<Register>();
505 DCHECK(locations->CanCall());
506 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +0100507 DCHECK(instruction_->IsInstanceFieldGet() ||
508 instruction_->IsStaticFieldGet() ||
509 instruction_->IsArrayGet() ||
510 instruction_->IsInstanceOf() ||
511 instruction_->IsCheckCast() ||
Roland Levillaindec8f632016-07-22 17:10:06 +0100512 (instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())
Roland Levillainc9285912015-12-18 10:38:42 +0000513 << "Unexpected instruction in read barrier for heap reference slow path: "
514 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000515
516 __ Bind(GetEntryLabel());
517 SaveLiveRegisters(codegen, locations);
518
519 // We may have to change the index's value, but as `index_` is a
520 // constant member (like other "inputs" of this slow path),
521 // introduce a copy of it, `index`.
522 Location index = index_;
523 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100524 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +0000525 if (instruction_->IsArrayGet()) {
526 // Compute the actual memory offset and store it in `index`.
527 Register index_reg = index_.AsRegister<Register>();
528 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
529 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
530 // We are about to change the value of `index_reg` (see the
531 // calls to art::arm::Thumb2Assembler::Lsl and
532 // art::arm::Thumb2Assembler::AddConstant below), but it has
533 // not been saved by the previous call to
534 // art::SlowPathCode::SaveLiveRegisters, as it is a
535 // callee-save register --
536 // art::SlowPathCode::SaveLiveRegisters does not consider
537 // callee-save registers, as it has been designed with the
538 // assumption that callee-save registers are supposed to be
539 // handled by the called function. So, as a callee-save
540 // register, `index_reg` _would_ eventually be saved onto
541 // the stack, but it would be too late: we would have
542 // changed its value earlier. Therefore, we manually save
543 // it here into another freely available register,
544 // `free_reg`, chosen of course among the caller-save
545 // registers (as a callee-save `free_reg` register would
546 // exhibit the same problem).
547 //
548 // Note we could have requested a temporary register from
549 // the register allocator instead; but we prefer not to, as
550 // this is a slow path, and we know we can find a
551 // caller-save register that is available.
552 Register free_reg = FindAvailableCallerSaveRegister(codegen);
553 __ Mov(free_reg, index_reg);
554 index_reg = free_reg;
555 index = Location::RegisterLocation(index_reg);
556 } else {
557 // The initial register stored in `index_` has already been
558 // saved in the call to art::SlowPathCode::SaveLiveRegisters
559 // (as it is not a callee-save register), so we can freely
560 // use it.
561 }
562 // Shifting the index value contained in `index_reg` by the scale
563 // factor (2) cannot overflow in practice, as the runtime is
564 // unable to allocate object arrays with a size larger than
565 // 2^26 - 1 (that is, 2^28 - 4 bytes).
566 __ Lsl(index_reg, index_reg, TIMES_4);
567 static_assert(
568 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
569 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
570 __ AddConstant(index_reg, index_reg, offset_);
571 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100572 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
573 // intrinsics, `index_` is not shifted by a scale factor of 2
574 // (as in the case of ArrayGet), as it is actually an offset
575 // to an object field within an object.
576 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000577 DCHECK(instruction_->GetLocations()->Intrinsified());
578 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
579 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
580 << instruction_->AsInvoke()->GetIntrinsic();
581 DCHECK_EQ(offset_, 0U);
582 DCHECK(index_.IsRegisterPair());
583 // UnsafeGet's offset location is a register pair, the low
584 // part contains the correct offset.
585 index = index_.ToLow();
586 }
587 }
588
589 // We're moving two or three locations to locations that could
590 // overlap, so we need a parallel move resolver.
591 InvokeRuntimeCallingConvention calling_convention;
592 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
593 parallel_move.AddMove(ref_,
594 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
595 Primitive::kPrimNot,
596 nullptr);
597 parallel_move.AddMove(obj_,
598 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
599 Primitive::kPrimNot,
600 nullptr);
601 if (index.IsValid()) {
602 parallel_move.AddMove(index,
603 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
604 Primitive::kPrimInt,
605 nullptr);
606 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
607 } else {
608 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
609 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
610 }
611 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
612 instruction_,
613 instruction_->GetDexPc(),
614 this);
615 CheckEntrypointTypes<
616 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
617 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
618
619 RestoreLiveRegisters(codegen, locations);
620 __ b(GetExitLabel());
621 }
622
623 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
624
625 private:
626 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
627 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
628 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
629 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
630 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
631 return static_cast<Register>(i);
632 }
633 }
634 // We shall never fail to find a free caller-save register, as
635 // there are more than two core caller-save registers on ARM
636 // (meaning it is possible to find one which is different from
637 // `ref` and `obj`).
638 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
639 LOG(FATAL) << "Could not find a free caller-save register";
640 UNREACHABLE();
641 }
642
Roland Levillain3b359c72015-11-17 19:35:12 +0000643 const Location out_;
644 const Location ref_;
645 const Location obj_;
646 const uint32_t offset_;
647 // An additional location containing an index to an array.
648 // Only used for HArrayGet and the UnsafeGetObject &
649 // UnsafeGetObjectVolatile intrinsics.
650 const Location index_;
651
652 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
653};
654
655// Slow path generating a read barrier for a GC root.
656class ReadBarrierForRootSlowPathARM : public SlowPathCode {
657 public:
658 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000659 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +0000660 DCHECK(kEmitCompilerReadBarrier);
661 }
Roland Levillain3b359c72015-11-17 19:35:12 +0000662
663 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
664 LocationSummary* locations = instruction_->GetLocations();
665 Register reg_out = out_.AsRegister<Register>();
666 DCHECK(locations->CanCall());
667 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +0000668 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
669 << "Unexpected instruction in read barrier for GC root slow path: "
670 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000671
672 __ Bind(GetEntryLabel());
673 SaveLiveRegisters(codegen, locations);
674
675 InvokeRuntimeCallingConvention calling_convention;
676 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
677 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
678 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
679 instruction_,
680 instruction_->GetDexPc(),
681 this);
682 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
683 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
684
685 RestoreLiveRegisters(codegen, locations);
686 __ b(GetExitLabel());
687 }
688
689 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
690
691 private:
Roland Levillain3b359c72015-11-17 19:35:12 +0000692 const Location out_;
693 const Location root_;
694
695 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
696};
697
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000698#undef __
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -0700699// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
700#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
Dave Allison20dfc792014-06-16 20:44:29 -0700701
Aart Bike9f37602015-10-09 11:15:55 -0700702inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700703 switch (cond) {
704 case kCondEQ: return EQ;
705 case kCondNE: return NE;
706 case kCondLT: return LT;
707 case kCondLE: return LE;
708 case kCondGT: return GT;
709 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700710 case kCondB: return LO;
711 case kCondBE: return LS;
712 case kCondA: return HI;
713 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700714 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100715 LOG(FATAL) << "Unreachable";
716 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700717}
718
Aart Bike9f37602015-10-09 11:15:55 -0700719// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100720inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700721 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100722 case kCondEQ: return EQ;
723 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700724 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100725 case kCondLT: return LO;
726 case kCondLE: return LS;
727 case kCondGT: return HI;
728 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700729 // Unsigned remain unchanged.
730 case kCondB: return LO;
731 case kCondBE: return LS;
732 case kCondA: return HI;
733 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700734 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100735 LOG(FATAL) << "Unreachable";
736 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700737}
738
Vladimir Markod6e069b2016-01-18 11:11:01 +0000739inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
740 // The ARM condition codes can express all the necessary branches, see the
741 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
742 // There is no dex instruction or HIR that would need the missing conditions
743 // "equal or unordered" or "not equal".
744 switch (cond) {
745 case kCondEQ: return EQ;
746 case kCondNE: return NE /* unordered */;
747 case kCondLT: return gt_bias ? CC : LT /* unordered */;
748 case kCondLE: return gt_bias ? LS : LE /* unordered */;
749 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
750 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
751 default:
752 LOG(FATAL) << "UNREACHABLE";
753 UNREACHABLE();
754 }
755}
756
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100757void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100758 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100759}
760
761void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100762 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100763}
764
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100765size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
766 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
767 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100768}
769
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100770size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
771 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
772 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100773}
774
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000775size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
776 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
777 return kArmWordSize;
778}
779
780size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
781 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
782 return kArmWordSize;
783}
784
Calin Juravle34166012014-12-19 17:22:29 +0000785CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000786 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100787 const CompilerOptions& compiler_options,
788 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000789 : CodeGenerator(graph,
790 kNumberOfCoreRegisters,
791 kNumberOfSRegisters,
792 kNumberOfRegisterPairs,
793 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
794 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000795 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
796 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100797 compiler_options,
798 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100799 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100800 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100801 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100802 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100803 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +0000804 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000805 uint32_literals_(std::less<uint32_t>(),
806 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko5233f932015-09-29 19:01:15 +0100807 method_patches_(MethodReferenceComparator(),
808 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
809 call_patches_(MethodReferenceComparator(),
810 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000811 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000812 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
813 boot_image_string_patches_(StringReferenceValueComparator(),
814 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
815 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100816 boot_image_type_patches_(TypeReferenceValueComparator(),
817 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
818 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000819 boot_image_address_patches_(std::less<uint32_t>(),
820 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700821 // Always save the LR register to mimic Quick.
822 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100823}
824
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000825void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
826 // Ensure that we fix up branches and literal loads and emit the literal pool.
827 __ FinalizeCode();
828
829 // Adjust native pc offsets in stack maps.
830 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
831 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
832 uint32_t new_position = __ GetAdjustedPosition(old_position);
833 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
834 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100835 // Adjust pc offsets for the disassembly information.
836 if (disasm_info_ != nullptr) {
837 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
838 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
839 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
840 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
841 it.second.start = __ GetAdjustedPosition(it.second.start);
842 it.second.end = __ GetAdjustedPosition(it.second.end);
843 }
844 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
845 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
846 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
847 }
848 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000849
850 CodeGenerator::Finalize(allocator);
851}
852
David Brazdil58282f42016-01-14 12:45:10 +0000853void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100854 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100855 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100856
857 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100858 blocked_core_registers_[SP] = true;
859 blocked_core_registers_[LR] = true;
860 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100861
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100862 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100863 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100864
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100865 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100866 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100867
David Brazdil58282f42016-01-14 12:45:10 +0000868 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100869 // Stubs do not save callee-save floating point registers. If the graph
870 // is debuggable, we need to deal with these registers differently. For
871 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000872 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
873 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
874 }
875 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100876
877 UpdateBlockedPairRegisters();
878}
879
880void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
881 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
882 ArmManagedRegister current =
883 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
884 if (blocked_core_registers_[current.AsRegisterPairLow()]
885 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
886 blocked_register_pairs_[i] = true;
887 }
888 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100889}
890
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100891InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -0800892 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100893 assembler_(codegen->GetAssembler()),
894 codegen_(codegen) {}
895
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000896void CodeGeneratorARM::ComputeSpillMask() {
897 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
898 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +0000899 // There is no easy instruction to restore just the PC on thumb2. We spill and
900 // restore another arbitrary register.
901 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000902 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
903 // We use vpush and vpop for saving and restoring floating point registers, which take
904 // a SRegister and the number of registers to save/restore after that SRegister. We
905 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
906 // but in the range.
907 if (fpu_spill_mask_ != 0) {
908 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
909 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
910 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
911 fpu_spill_mask_ |= (1 << i);
912 }
913 }
914}
915
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100916static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100917 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100918}
919
920static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100921 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100922}
923
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000924void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000925 bool skip_overflow_check =
926 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000927 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000928 __ Bind(&frame_entry_label_);
929
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000930 if (HasEmptyFrame()) {
931 return;
932 }
933
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100934 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000935 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
936 __ LoadFromOffset(kLoadWord, IP, IP, 0);
937 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100938 }
939
Andreas Gampe501fd632015-09-10 16:11:06 -0700940 __ PushList(core_spill_mask_);
941 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
942 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000943 if (fpu_spill_mask_ != 0) {
944 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
945 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100946 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100947 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000948 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100949 int adjust = GetFrameSize() - FrameEntrySpillSize();
950 __ AddConstant(SP, -adjust);
951 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100952 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000953}
954
955void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000956 if (HasEmptyFrame()) {
957 __ bx(LR);
958 return;
959 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100960 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100961 int adjust = GetFrameSize() - FrameEntrySpillSize();
962 __ AddConstant(SP, adjust);
963 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000964 if (fpu_spill_mask_ != 0) {
965 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
966 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -0700967 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100968 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000969 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700970 // Pop LR into PC to return.
971 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
972 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
973 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100974 __ cfi().RestoreState();
975 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000976}
977
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100978void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700979 Label* label = GetLabelOf(block);
980 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000981}
982
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100983Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100984 switch (type) {
985 case Primitive::kPrimBoolean:
986 case Primitive::kPrimByte:
987 case Primitive::kPrimChar:
988 case Primitive::kPrimShort:
989 case Primitive::kPrimInt:
990 case Primitive::kPrimNot: {
991 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000992 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100993 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100994 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100995 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000996 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100997 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100998 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100999
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001000 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001001 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001002 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001003 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001004 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001005 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001006 if (calling_convention.GetRegisterAt(index) == R1) {
1007 // Skip R1, and use R2_R3 instead.
1008 gp_index_++;
1009 index++;
1010 }
1011 }
1012 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1013 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001014 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001015
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001016 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001017 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001018 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001019 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1020 }
1021 }
1022
1023 case Primitive::kPrimFloat: {
1024 uint32_t stack_index = stack_index_++;
1025 if (float_index_ % 2 == 0) {
1026 float_index_ = std::max(double_index_, float_index_);
1027 }
1028 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1029 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1030 } else {
1031 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1032 }
1033 }
1034
1035 case Primitive::kPrimDouble: {
1036 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1037 uint32_t stack_index = stack_index_;
1038 stack_index_ += 2;
1039 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1040 uint32_t index = double_index_;
1041 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001042 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001043 calling_convention.GetFpuRegisterAt(index),
1044 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001045 DCHECK(ExpectedPairLayout(result));
1046 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001047 } else {
1048 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001049 }
1050 }
1051
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001052 case Primitive::kPrimVoid:
1053 LOG(FATAL) << "Unexpected parameter type " << type;
1054 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001055 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001056 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001057}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001058
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001059Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001060 switch (type) {
1061 case Primitive::kPrimBoolean:
1062 case Primitive::kPrimByte:
1063 case Primitive::kPrimChar:
1064 case Primitive::kPrimShort:
1065 case Primitive::kPrimInt:
1066 case Primitive::kPrimNot: {
1067 return Location::RegisterLocation(R0);
1068 }
1069
1070 case Primitive::kPrimFloat: {
1071 return Location::FpuRegisterLocation(S0);
1072 }
1073
1074 case Primitive::kPrimLong: {
1075 return Location::RegisterPairLocation(R0, R1);
1076 }
1077
1078 case Primitive::kPrimDouble: {
1079 return Location::FpuRegisterPairLocation(S0, S1);
1080 }
1081
1082 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001083 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001084 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001085
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001086 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001087}
1088
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001089Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1090 return Location::RegisterLocation(kMethodRegisterArgument);
1091}
1092
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001093void CodeGeneratorARM::Move32(Location destination, Location source) {
1094 if (source.Equals(destination)) {
1095 return;
1096 }
1097 if (destination.IsRegister()) {
1098 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001099 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001100 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001101 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001102 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001103 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001104 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001105 } else if (destination.IsFpuRegister()) {
1106 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001107 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001108 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001110 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001111 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001112 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001113 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001114 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001116 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001117 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001118 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001119 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001120 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001121 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1122 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001123 }
1124 }
1125}
1126
1127void CodeGeneratorARM::Move64(Location destination, Location source) {
1128 if (source.Equals(destination)) {
1129 return;
1130 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001131 if (destination.IsRegisterPair()) {
1132 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001133 EmitParallelMoves(
1134 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1135 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001136 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001137 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001138 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1139 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001140 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001141 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001142 } else if (source.IsFpuRegisterPair()) {
1143 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1144 destination.AsRegisterPairHigh<Register>(),
1145 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001146 } else {
1147 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001148 DCHECK(ExpectedPairLayout(destination));
1149 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1150 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001151 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001152 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001153 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001154 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1155 SP,
1156 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001157 } else if (source.IsRegisterPair()) {
1158 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1159 source.AsRegisterPairLow<Register>(),
1160 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001161 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001162 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001163 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001164 } else {
1165 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001166 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001167 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001168 if (source.AsRegisterPairLow<Register>() == R1) {
1169 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001170 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1171 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001172 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001173 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001174 SP, destination.GetStackIndex());
1175 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001176 } else if (source.IsFpuRegisterPair()) {
1177 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1178 SP,
1179 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001180 } else {
1181 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001182 EmitParallelMoves(
1183 Location::StackSlot(source.GetStackIndex()),
1184 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001185 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001186 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001187 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1188 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001189 }
1190 }
1191}
1192
Calin Juravle175dc732015-08-25 15:42:32 +01001193void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1194 DCHECK(location.IsRegister());
1195 __ LoadImmediate(location.AsRegister<Register>(), value);
1196}
1197
Calin Juravlee460d1d2015-09-29 04:52:17 +01001198void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001199 HParallelMove move(GetGraph()->GetArena());
1200 move.AddMove(src, dst, dst_type, nullptr);
1201 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001202}
1203
1204void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1205 if (location.IsRegister()) {
1206 locations->AddTemp(location);
1207 } else if (location.IsRegisterPair()) {
1208 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1209 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1210 } else {
1211 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1212 }
1213}
1214
Calin Juravle175dc732015-08-25 15:42:32 +01001215void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1216 HInstruction* instruction,
1217 uint32_t dex_pc,
1218 SlowPathCode* slow_path) {
Andreas Gampe542451c2016-07-26 09:02:02 -07001219 InvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value(),
Calin Juravle175dc732015-08-25 15:42:32 +01001220 instruction,
1221 dex_pc,
1222 slow_path);
1223}
1224
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001225void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1226 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001227 uint32_t dex_pc,
1228 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001229 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001230 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1231 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001232 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001233}
1234
Roland Levillaindec8f632016-07-22 17:10:06 +01001235void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1236 HInstruction* instruction,
1237 SlowPathCode* slow_path) {
1238 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1239 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1240 __ blx(LR);
1241}
1242
David Brazdilfc6a86a2015-06-26 10:33:45 +00001243void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001244 DCHECK(!successor->IsExitBlock());
1245
1246 HBasicBlock* block = got->GetBlock();
1247 HInstruction* previous = got->GetPrevious();
1248
1249 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001250 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001251 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1252 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1253 return;
1254 }
1255
1256 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1257 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1258 }
1259 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001260 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001261 }
1262}
1263
David Brazdilfc6a86a2015-06-26 10:33:45 +00001264void LocationsBuilderARM::VisitGoto(HGoto* got) {
1265 got->SetLocations(nullptr);
1266}
1267
1268void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1269 HandleGoto(got, got->GetSuccessor());
1270}
1271
1272void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1273 try_boundary->SetLocations(nullptr);
1274}
1275
1276void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1277 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1278 if (!successor->IsExitBlock()) {
1279 HandleGoto(try_boundary, successor);
1280 }
1281}
1282
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001283void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001284 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001285}
1286
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001287void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001288}
1289
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001290void InstructionCodeGeneratorARM::GenerateVcmp(HInstruction* instruction) {
1291 Primitive::Type type = instruction->InputAt(0)->GetType();
1292 Location lhs_loc = instruction->GetLocations()->InAt(0);
1293 Location rhs_loc = instruction->GetLocations()->InAt(1);
1294 if (rhs_loc.IsConstant()) {
1295 // 0.0 is the only immediate that can be encoded directly in
1296 // a VCMP instruction.
1297 //
1298 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1299 // specify that in a floating-point comparison, positive zero
1300 // and negative zero are considered equal, so we can use the
1301 // literal 0.0 for both cases here.
1302 //
1303 // Note however that some methods (Float.equal, Float.compare,
1304 // Float.compareTo, Double.equal, Double.compare,
1305 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1306 // StrictMath.min) consider 0.0 to be (strictly) greater than
1307 // -0.0. So if we ever translate calls to these methods into a
1308 // HCompare instruction, we must handle the -0.0 case with
1309 // care here.
1310 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1311 if (type == Primitive::kPrimFloat) {
1312 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1313 } else {
1314 DCHECK_EQ(type, Primitive::kPrimDouble);
1315 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1316 }
1317 } else {
1318 if (type == Primitive::kPrimFloat) {
1319 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1320 } else {
1321 DCHECK_EQ(type, Primitive::kPrimDouble);
1322 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1323 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1324 }
1325 }
1326}
1327
Roland Levillain4fa13f62015-07-06 18:11:54 +01001328void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1329 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001330 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001331 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001332 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001333}
1334
1335void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1336 Label* true_label,
1337 Label* false_label) {
1338 LocationSummary* locations = cond->GetLocations();
1339 Location left = locations->InAt(0);
1340 Location right = locations->InAt(1);
1341 IfCondition if_cond = cond->GetCondition();
1342
1343 Register left_high = left.AsRegisterPairHigh<Register>();
1344 Register left_low = left.AsRegisterPairLow<Register>();
1345 IfCondition true_high_cond = if_cond;
1346 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001347 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001348
1349 // Set the conditions for the test, remembering that == needs to be
1350 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001351 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001352 switch (if_cond) {
1353 case kCondEQ:
1354 case kCondNE:
1355 // Nothing to do.
1356 break;
1357 case kCondLT:
1358 false_high_cond = kCondGT;
1359 break;
1360 case kCondLE:
1361 true_high_cond = kCondLT;
1362 break;
1363 case kCondGT:
1364 false_high_cond = kCondLT;
1365 break;
1366 case kCondGE:
1367 true_high_cond = kCondGT;
1368 break;
Aart Bike9f37602015-10-09 11:15:55 -07001369 case kCondB:
1370 false_high_cond = kCondA;
1371 break;
1372 case kCondBE:
1373 true_high_cond = kCondB;
1374 break;
1375 case kCondA:
1376 false_high_cond = kCondB;
1377 break;
1378 case kCondAE:
1379 true_high_cond = kCondA;
1380 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001381 }
1382 if (right.IsConstant()) {
1383 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1384 int32_t val_low = Low32Bits(value);
1385 int32_t val_high = High32Bits(value);
1386
Vladimir Markoac6ac102015-12-17 12:14:00 +00001387 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001388 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001389 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001390 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001391 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001392 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001393 __ b(true_label, ARMCondition(true_high_cond));
1394 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001395 }
1396 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001397 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001398 } else {
1399 Register right_high = right.AsRegisterPairHigh<Register>();
1400 Register right_low = right.AsRegisterPairLow<Register>();
1401
1402 __ cmp(left_high, ShifterOperand(right_high));
1403 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001404 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001405 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001406 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001407 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001408 __ b(true_label, ARMCondition(true_high_cond));
1409 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001410 }
1411 // Must be equal high, so compare the lows.
1412 __ cmp(left_low, ShifterOperand(right_low));
1413 }
1414 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001415 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001416 __ b(true_label, final_condition);
1417}
1418
David Brazdil0debae72015-11-12 18:37:00 +00001419void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1420 Label* true_target_in,
1421 Label* false_target_in) {
1422 // Generated branching requires both targets to be explicit. If either of the
1423 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1424 Label fallthrough_target;
1425 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1426 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1427
Roland Levillain4fa13f62015-07-06 18:11:54 +01001428 Primitive::Type type = condition->InputAt(0)->GetType();
1429 switch (type) {
1430 case Primitive::kPrimLong:
1431 GenerateLongComparesAndJumps(condition, true_target, false_target);
1432 break;
1433 case Primitive::kPrimFloat:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001434 case Primitive::kPrimDouble:
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001435 GenerateVcmp(condition);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001436 GenerateFPJumps(condition, true_target, false_target);
1437 break;
1438 default:
1439 LOG(FATAL) << "Unexpected compare type " << type;
1440 }
1441
David Brazdil0debae72015-11-12 18:37:00 +00001442 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001443 __ b(false_target);
1444 }
David Brazdil0debae72015-11-12 18:37:00 +00001445
1446 if (fallthrough_target.IsLinked()) {
1447 __ Bind(&fallthrough_target);
1448 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001449}
1450
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001451void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001452 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001453 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001454 Label* false_target) {
1455 HInstruction* cond = instruction->InputAt(condition_input_index);
1456
1457 if (true_target == nullptr && false_target == nullptr) {
1458 // Nothing to do. The code always falls through.
1459 return;
1460 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001461 // Constant condition, statically compared against "true" (integer value 1).
1462 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001463 if (true_target != nullptr) {
1464 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001465 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001466 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001467 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001468 if (false_target != nullptr) {
1469 __ b(false_target);
1470 }
1471 }
1472 return;
1473 }
1474
1475 // The following code generates these patterns:
1476 // (1) true_target == nullptr && false_target != nullptr
1477 // - opposite condition true => branch to false_target
1478 // (2) true_target != nullptr && false_target == nullptr
1479 // - condition true => branch to true_target
1480 // (3) true_target != nullptr && false_target != nullptr
1481 // - condition true => branch to true_target
1482 // - branch to false_target
1483 if (IsBooleanValueOrMaterializedCondition(cond)) {
1484 // Condition has been materialized, compare the output to 0.
1485 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1486 DCHECK(cond_val.IsRegister());
1487 if (true_target == nullptr) {
1488 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1489 } else {
1490 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001491 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001492 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001493 // Condition has not been materialized. Use its inputs as the comparison and
1494 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001495 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001496
1497 // If this is a long or FP comparison that has been folded into
1498 // the HCondition, generate the comparison directly.
1499 Primitive::Type type = condition->InputAt(0)->GetType();
1500 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1501 GenerateCompareTestAndBranch(condition, true_target, false_target);
1502 return;
1503 }
1504
1505 LocationSummary* locations = cond->GetLocations();
1506 DCHECK(locations->InAt(0).IsRegister());
1507 Register left = locations->InAt(0).AsRegister<Register>();
1508 Location right = locations->InAt(1);
1509 if (right.IsRegister()) {
1510 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001511 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001512 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001513 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001514 }
1515 if (true_target == nullptr) {
1516 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1517 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001518 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001519 }
Dave Allison20dfc792014-06-16 20:44:29 -07001520 }
David Brazdil0debae72015-11-12 18:37:00 +00001521
1522 // If neither branch falls through (case 3), the conditional branch to `true_target`
1523 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1524 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001525 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001526 }
1527}
1528
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001529void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001530 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1531 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001532 locations->SetInAt(0, Location::RequiresRegister());
1533 }
1534}
1535
1536void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001537 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1538 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1539 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1540 nullptr : codegen_->GetLabelOf(true_successor);
1541 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1542 nullptr : codegen_->GetLabelOf(false_successor);
1543 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001544}
1545
1546void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1547 LocationSummary* locations = new (GetGraph()->GetArena())
1548 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001549 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001550 locations->SetInAt(0, Location::RequiresRegister());
1551 }
1552}
1553
1554void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001555 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001556 GenerateTestAndBranch(deoptimize,
1557 /* condition_input_index */ 0,
1558 slow_path->GetEntryLabel(),
1559 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001560}
Dave Allison20dfc792014-06-16 20:44:29 -07001561
David Brazdil74eb1b22015-12-14 11:44:01 +00001562void LocationsBuilderARM::VisitSelect(HSelect* select) {
1563 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1564 if (Primitive::IsFloatingPointType(select->GetType())) {
1565 locations->SetInAt(0, Location::RequiresFpuRegister());
1566 locations->SetInAt(1, Location::RequiresFpuRegister());
1567 } else {
1568 locations->SetInAt(0, Location::RequiresRegister());
1569 locations->SetInAt(1, Location::RequiresRegister());
1570 }
1571 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1572 locations->SetInAt(2, Location::RequiresRegister());
1573 }
1574 locations->SetOut(Location::SameAsFirstInput());
1575}
1576
1577void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1578 LocationSummary* locations = select->GetLocations();
1579 Label false_target;
1580 GenerateTestAndBranch(select,
1581 /* condition_input_index */ 2,
1582 /* true_target */ nullptr,
1583 &false_target);
1584 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1585 __ Bind(&false_target);
1586}
1587
David Srbecky0cf44932015-12-09 14:09:59 +00001588void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1589 new (GetGraph()->GetArena()) LocationSummary(info);
1590}
1591
David Srbeckyd28f4a02016-03-14 17:14:24 +00001592void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
1593 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001594}
1595
1596void CodeGeneratorARM::GenerateNop() {
1597 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001598}
1599
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001600void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001601 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001602 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001603 // Handle the long/FP comparisons made in instruction simplification.
1604 switch (cond->InputAt(0)->GetType()) {
1605 case Primitive::kPrimLong:
1606 locations->SetInAt(0, Location::RequiresRegister());
1607 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001608 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001609 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1610 }
1611 break;
1612
1613 case Primitive::kPrimFloat:
1614 case Primitive::kPrimDouble:
1615 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001616 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001617 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001618 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1619 }
1620 break;
1621
1622 default:
1623 locations->SetInAt(0, Location::RequiresRegister());
1624 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001625 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001626 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1627 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001628 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001629}
1630
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001631void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001632 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001633 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001634 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001635
1636 LocationSummary* locations = cond->GetLocations();
1637 Location left = locations->InAt(0);
1638 Location right = locations->InAt(1);
1639 Register out = locations->Out().AsRegister<Register>();
1640 Label true_label, false_label;
1641
1642 switch (cond->InputAt(0)->GetType()) {
1643 default: {
1644 // Integer case.
1645 if (right.IsRegister()) {
1646 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1647 } else {
1648 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001649 __ CmpConstant(left.AsRegister<Register>(),
1650 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001651 }
Aart Bike9f37602015-10-09 11:15:55 -07001652 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001653 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001654 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001655 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001656 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001657 return;
1658 }
1659 case Primitive::kPrimLong:
1660 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1661 break;
1662 case Primitive::kPrimFloat:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001663 case Primitive::kPrimDouble:
Vladimir Marko37dd80d2016-08-01 17:41:45 +01001664 GenerateVcmp(cond);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001665 GenerateFPJumps(cond, &true_label, &false_label);
1666 break;
1667 }
1668
1669 // Convert the jumps into the result.
1670 Label done_label;
1671
1672 // False case: result = 0.
1673 __ Bind(&false_label);
1674 __ LoadImmediate(out, 0);
1675 __ b(&done_label);
1676
1677 // True case: result = 1.
1678 __ Bind(&true_label);
1679 __ LoadImmediate(out, 1);
1680 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001681}
1682
1683void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001684 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001685}
1686
1687void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001688 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001689}
1690
1691void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001692 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001693}
1694
1695void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001696 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001697}
1698
1699void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001700 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001701}
1702
1703void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001704 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001705}
1706
1707void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001708 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001709}
1710
1711void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001712 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001713}
1714
1715void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001716 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001717}
1718
1719void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001720 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001721}
1722
1723void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001724 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001725}
1726
1727void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001728 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001729}
1730
Aart Bike9f37602015-10-09 11:15:55 -07001731void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001732 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001733}
1734
1735void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001736 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001737}
1738
1739void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001740 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001741}
1742
1743void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001744 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001745}
1746
1747void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001748 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001749}
1750
1751void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001752 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001753}
1754
1755void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001756 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001757}
1758
1759void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001760 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001761}
1762
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001763void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001764 LocationSummary* locations =
1765 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001766 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001767}
1768
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001769void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001770 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001771}
1772
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001773void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1774 LocationSummary* locations =
1775 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1776 locations->SetOut(Location::ConstantLocation(constant));
1777}
1778
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001779void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001780 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001781}
1782
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001783void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001784 LocationSummary* locations =
1785 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001786 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001787}
1788
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001789void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001790 // Will be generated at use site.
1791}
1792
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001793void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1794 LocationSummary* locations =
1795 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1796 locations->SetOut(Location::ConstantLocation(constant));
1797}
1798
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001799void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001800 // Will be generated at use site.
1801}
1802
1803void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1804 LocationSummary* locations =
1805 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1806 locations->SetOut(Location::ConstantLocation(constant));
1807}
1808
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001809void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001810 // Will be generated at use site.
1811}
1812
Calin Juravle27df7582015-04-17 19:12:31 +01001813void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1814 memory_barrier->SetLocations(nullptr);
1815}
1816
1817void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00001818 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01001819}
1820
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001821void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001822 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001823}
1824
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001825void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001826 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001827}
1828
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001829void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001830 LocationSummary* locations =
1831 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001832 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001833}
1834
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001835void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001836 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001837}
1838
Calin Juravle175dc732015-08-25 15:42:32 +01001839void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1840 // The trampoline uses the same calling convention as dex calling conventions,
1841 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1842 // the method_idx.
1843 HandleInvoke(invoke);
1844}
1845
1846void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1847 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1848}
1849
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001850void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001851 // Explicit clinit checks triggered by static invokes must have been pruned by
1852 // art::PrepareForRegisterAllocation.
1853 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001854
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001855 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001856 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001857 codegen_->GetInstructionSetFeatures());
1858 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001859 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1860 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1861 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001862 return;
1863 }
1864
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001865 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001866
1867 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1868 if (invoke->HasPcRelativeDexCache()) {
1869 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1870 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001871}
1872
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001873static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1874 if (invoke->GetLocations()->Intrinsified()) {
1875 IntrinsicCodeGeneratorARM intrinsic(codegen);
1876 intrinsic.Dispatch(invoke);
1877 return true;
1878 }
1879 return false;
1880}
1881
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001882void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001883 // Explicit clinit checks triggered by static invokes must have been pruned by
1884 // art::PrepareForRegisterAllocation.
1885 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001886
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001887 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1888 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001889 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001890
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001891 LocationSummary* locations = invoke->GetLocations();
1892 codegen_->GenerateStaticOrDirectCall(
1893 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001894 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001895}
1896
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001897void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001898 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001899 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001900}
1901
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001902void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001903 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001904 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001905 codegen_->GetInstructionSetFeatures());
1906 if (intrinsic.TryDispatch(invoke)) {
1907 return;
1908 }
1909
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001910 HandleInvoke(invoke);
1911}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001912
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001913void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001914 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1915 return;
1916 }
1917
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001918 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001919 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001920 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001921}
1922
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001923void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1924 HandleInvoke(invoke);
1925 // Add the hidden argument.
1926 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1927}
1928
1929void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1930 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001931 LocationSummary* locations = invoke->GetLocations();
1932 Register temp = locations->GetTemp(0).AsRegister<Register>();
1933 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001934 Location receiver = locations->InAt(0);
1935 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1936
Roland Levillain3b359c72015-11-17 19:35:12 +00001937 // Set the hidden argument. This is safe to do this here, as R12
1938 // won't be modified thereafter, before the `blx` (call) instruction.
1939 DCHECK_EQ(R12, hidden_reg);
1940 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001941
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001942 if (receiver.IsStackSlot()) {
1943 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00001944 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001945 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1946 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00001947 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00001948 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001949 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001950 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00001951 // Instead of simply (possibly) unpoisoning `temp` here, we should
1952 // emit a read barrier for the previous class reference load.
1953 // However this is not required in practice, as this is an
1954 // intermediate/temporary reference and because the current
1955 // concurrent copying collector keeps the from-space memory
1956 // intact/accessible until the end of the marking phase (the
1957 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01001958 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00001959 __ LoadFromOffset(kLoadWord, temp, temp,
1960 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
1961 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00001962 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001963 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00001964 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001965 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07001966 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001967 // LR = temp->GetEntryPoint();
1968 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1969 // LR();
1970 __ blx(LR);
1971 DCHECK(!codegen_->IsLeafMethod());
1972 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1973}
1974
Roland Levillain88cb1752014-10-20 16:36:47 +01001975void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1976 LocationSummary* locations =
1977 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1978 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001979 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001980 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001981 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1982 break;
1983 }
1984 case Primitive::kPrimLong: {
1985 locations->SetInAt(0, Location::RequiresRegister());
1986 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001987 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001988 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001989
Roland Levillain88cb1752014-10-20 16:36:47 +01001990 case Primitive::kPrimFloat:
1991 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001992 locations->SetInAt(0, Location::RequiresFpuRegister());
1993 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001994 break;
1995
1996 default:
1997 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1998 }
1999}
2000
2001void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2002 LocationSummary* locations = neg->GetLocations();
2003 Location out = locations->Out();
2004 Location in = locations->InAt(0);
2005 switch (neg->GetResultType()) {
2006 case Primitive::kPrimInt:
2007 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002008 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01002009 break;
2010
2011 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002012 DCHECK(in.IsRegisterPair());
2013 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2014 __ rsbs(out.AsRegisterPairLow<Register>(),
2015 in.AsRegisterPairLow<Register>(),
2016 ShifterOperand(0));
2017 // We cannot emit an RSC (Reverse Subtract with Carry)
2018 // instruction here, as it does not exist in the Thumb-2
2019 // instruction set. We use the following approach
2020 // using SBC and SUB instead.
2021 //
2022 // out.hi = -C
2023 __ sbc(out.AsRegisterPairHigh<Register>(),
2024 out.AsRegisterPairHigh<Register>(),
2025 ShifterOperand(out.AsRegisterPairHigh<Register>()));
2026 // out.hi = out.hi - in.hi
2027 __ sub(out.AsRegisterPairHigh<Register>(),
2028 out.AsRegisterPairHigh<Register>(),
2029 ShifterOperand(in.AsRegisterPairHigh<Register>()));
2030 break;
2031
Roland Levillain88cb1752014-10-20 16:36:47 +01002032 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002033 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002034 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002035 break;
2036
Roland Levillain88cb1752014-10-20 16:36:47 +01002037 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002038 DCHECK(in.IsFpuRegisterPair());
2039 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2040 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01002041 break;
2042
2043 default:
2044 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2045 }
2046}
2047
Roland Levillaindff1f282014-11-05 14:15:05 +00002048void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002049 Primitive::Type result_type = conversion->GetResultType();
2050 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002051 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002052
Roland Levillain5b3ee562015-04-14 16:02:41 +01002053 // The float-to-long, double-to-long and long-to-float type conversions
2054 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002055 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002056 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2057 && result_type == Primitive::kPrimLong)
2058 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002059 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00002060 : LocationSummary::kNoCall;
2061 LocationSummary* locations =
2062 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2063
David Brazdilb2bd1c52015-03-25 11:17:37 +00002064 // The Java language does not allow treating boolean as an integral type but
2065 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002066
Roland Levillaindff1f282014-11-05 14:15:05 +00002067 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002068 case Primitive::kPrimByte:
2069 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002070 case Primitive::kPrimLong:
2071 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002072 case Primitive::kPrimBoolean:
2073 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002074 case Primitive::kPrimShort:
2075 case Primitive::kPrimInt:
2076 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002077 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002078 locations->SetInAt(0, Location::RequiresRegister());
2079 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2080 break;
2081
2082 default:
2083 LOG(FATAL) << "Unexpected type conversion from " << input_type
2084 << " to " << result_type;
2085 }
2086 break;
2087
Roland Levillain01a8d712014-11-14 16:27:39 +00002088 case Primitive::kPrimShort:
2089 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002090 case Primitive::kPrimLong:
2091 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002092 case Primitive::kPrimBoolean:
2093 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002094 case Primitive::kPrimByte:
2095 case Primitive::kPrimInt:
2096 case Primitive::kPrimChar:
2097 // Processing a Dex `int-to-short' instruction.
2098 locations->SetInAt(0, Location::RequiresRegister());
2099 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2100 break;
2101
2102 default:
2103 LOG(FATAL) << "Unexpected type conversion from " << input_type
2104 << " to " << result_type;
2105 }
2106 break;
2107
Roland Levillain946e1432014-11-11 17:35:19 +00002108 case Primitive::kPrimInt:
2109 switch (input_type) {
2110 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002111 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002112 locations->SetInAt(0, Location::Any());
2113 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2114 break;
2115
2116 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002117 // Processing a Dex `float-to-int' instruction.
2118 locations->SetInAt(0, Location::RequiresFpuRegister());
2119 locations->SetOut(Location::RequiresRegister());
2120 locations->AddTemp(Location::RequiresFpuRegister());
2121 break;
2122
Roland Levillain946e1432014-11-11 17:35:19 +00002123 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002124 // Processing a Dex `double-to-int' instruction.
2125 locations->SetInAt(0, Location::RequiresFpuRegister());
2126 locations->SetOut(Location::RequiresRegister());
2127 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002128 break;
2129
2130 default:
2131 LOG(FATAL) << "Unexpected type conversion from " << input_type
2132 << " to " << result_type;
2133 }
2134 break;
2135
Roland Levillaindff1f282014-11-05 14:15:05 +00002136 case Primitive::kPrimLong:
2137 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002138 case Primitive::kPrimBoolean:
2139 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002140 case Primitive::kPrimByte:
2141 case Primitive::kPrimShort:
2142 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002143 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002144 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002145 locations->SetInAt(0, Location::RequiresRegister());
2146 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2147 break;
2148
Roland Levillain624279f2014-12-04 11:54:28 +00002149 case Primitive::kPrimFloat: {
2150 // Processing a Dex `float-to-long' instruction.
2151 InvokeRuntimeCallingConvention calling_convention;
2152 locations->SetInAt(0, Location::FpuRegisterLocation(
2153 calling_convention.GetFpuRegisterAt(0)));
2154 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2155 break;
2156 }
2157
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002158 case Primitive::kPrimDouble: {
2159 // Processing a Dex `double-to-long' instruction.
2160 InvokeRuntimeCallingConvention calling_convention;
2161 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2162 calling_convention.GetFpuRegisterAt(0),
2163 calling_convention.GetFpuRegisterAt(1)));
2164 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002165 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002166 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002167
2168 default:
2169 LOG(FATAL) << "Unexpected type conversion from " << input_type
2170 << " to " << result_type;
2171 }
2172 break;
2173
Roland Levillain981e4542014-11-14 11:47:14 +00002174 case Primitive::kPrimChar:
2175 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002176 case Primitive::kPrimLong:
2177 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002178 case Primitive::kPrimBoolean:
2179 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002180 case Primitive::kPrimByte:
2181 case Primitive::kPrimShort:
2182 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002183 // Processing a Dex `int-to-char' instruction.
2184 locations->SetInAt(0, Location::RequiresRegister());
2185 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2186 break;
2187
2188 default:
2189 LOG(FATAL) << "Unexpected type conversion from " << input_type
2190 << " to " << result_type;
2191 }
2192 break;
2193
Roland Levillaindff1f282014-11-05 14:15:05 +00002194 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002195 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002196 case Primitive::kPrimBoolean:
2197 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002198 case Primitive::kPrimByte:
2199 case Primitive::kPrimShort:
2200 case Primitive::kPrimInt:
2201 case Primitive::kPrimChar:
2202 // Processing a Dex `int-to-float' instruction.
2203 locations->SetInAt(0, Location::RequiresRegister());
2204 locations->SetOut(Location::RequiresFpuRegister());
2205 break;
2206
Roland Levillain5b3ee562015-04-14 16:02:41 +01002207 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002208 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002209 InvokeRuntimeCallingConvention calling_convention;
2210 locations->SetInAt(0, Location::RegisterPairLocation(
2211 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2212 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002213 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002214 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002215
Roland Levillaincff13742014-11-17 14:32:17 +00002216 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002217 // Processing a Dex `double-to-float' instruction.
2218 locations->SetInAt(0, Location::RequiresFpuRegister());
2219 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002220 break;
2221
2222 default:
2223 LOG(FATAL) << "Unexpected type conversion from " << input_type
2224 << " to " << result_type;
2225 };
2226 break;
2227
Roland Levillaindff1f282014-11-05 14:15:05 +00002228 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002229 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002230 case Primitive::kPrimBoolean:
2231 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002232 case Primitive::kPrimByte:
2233 case Primitive::kPrimShort:
2234 case Primitive::kPrimInt:
2235 case Primitive::kPrimChar:
2236 // Processing a Dex `int-to-double' instruction.
2237 locations->SetInAt(0, Location::RequiresRegister());
2238 locations->SetOut(Location::RequiresFpuRegister());
2239 break;
2240
2241 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002242 // Processing a Dex `long-to-double' instruction.
2243 locations->SetInAt(0, Location::RequiresRegister());
2244 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002245 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002246 locations->AddTemp(Location::RequiresFpuRegister());
2247 break;
2248
Roland Levillaincff13742014-11-17 14:32:17 +00002249 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002250 // Processing a Dex `float-to-double' instruction.
2251 locations->SetInAt(0, Location::RequiresFpuRegister());
2252 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002253 break;
2254
2255 default:
2256 LOG(FATAL) << "Unexpected type conversion from " << input_type
2257 << " to " << result_type;
2258 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002259 break;
2260
2261 default:
2262 LOG(FATAL) << "Unexpected type conversion from " << input_type
2263 << " to " << result_type;
2264 }
2265}
2266
2267void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2268 LocationSummary* locations = conversion->GetLocations();
2269 Location out = locations->Out();
2270 Location in = locations->InAt(0);
2271 Primitive::Type result_type = conversion->GetResultType();
2272 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002273 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002274 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002275 case Primitive::kPrimByte:
2276 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002277 case Primitive::kPrimLong:
2278 // Type conversion from long to byte is a result of code transformations.
2279 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2280 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002281 case Primitive::kPrimBoolean:
2282 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002283 case Primitive::kPrimShort:
2284 case Primitive::kPrimInt:
2285 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002286 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002287 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002288 break;
2289
2290 default:
2291 LOG(FATAL) << "Unexpected type conversion from " << input_type
2292 << " to " << result_type;
2293 }
2294 break;
2295
Roland Levillain01a8d712014-11-14 16:27:39 +00002296 case Primitive::kPrimShort:
2297 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002298 case Primitive::kPrimLong:
2299 // Type conversion from long to short is a result of code transformations.
2300 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2301 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002302 case Primitive::kPrimBoolean:
2303 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002304 case Primitive::kPrimByte:
2305 case Primitive::kPrimInt:
2306 case Primitive::kPrimChar:
2307 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002308 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002309 break;
2310
2311 default:
2312 LOG(FATAL) << "Unexpected type conversion from " << input_type
2313 << " to " << result_type;
2314 }
2315 break;
2316
Roland Levillain946e1432014-11-11 17:35:19 +00002317 case Primitive::kPrimInt:
2318 switch (input_type) {
2319 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002320 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002321 DCHECK(out.IsRegister());
2322 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002323 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002324 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002325 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002326 } else {
2327 DCHECK(in.IsConstant());
2328 DCHECK(in.GetConstant()->IsLongConstant());
2329 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002330 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002331 }
2332 break;
2333
Roland Levillain3f8f9362014-12-02 17:45:01 +00002334 case Primitive::kPrimFloat: {
2335 // Processing a Dex `float-to-int' instruction.
2336 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002337 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00002338 __ vmovrs(out.AsRegister<Register>(), temp);
2339 break;
2340 }
2341
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002342 case Primitive::kPrimDouble: {
2343 // Processing a Dex `double-to-int' instruction.
2344 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01002345 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002346 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002347 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002348 }
Roland Levillain946e1432014-11-11 17:35:19 +00002349
2350 default:
2351 LOG(FATAL) << "Unexpected type conversion from " << input_type
2352 << " to " << result_type;
2353 }
2354 break;
2355
Roland Levillaindff1f282014-11-05 14:15:05 +00002356 case Primitive::kPrimLong:
2357 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002358 case Primitive::kPrimBoolean:
2359 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002360 case Primitive::kPrimByte:
2361 case Primitive::kPrimShort:
2362 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002363 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002364 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002365 DCHECK(out.IsRegisterPair());
2366 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002367 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002368 // Sign extension.
2369 __ Asr(out.AsRegisterPairHigh<Register>(),
2370 out.AsRegisterPairLow<Register>(),
2371 31);
2372 break;
2373
2374 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002375 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002376 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2377 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002378 conversion->GetDexPc(),
2379 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002380 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002381 break;
2382
Roland Levillaindff1f282014-11-05 14:15:05 +00002383 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002384 // Processing a Dex `double-to-long' instruction.
2385 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2386 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002387 conversion->GetDexPc(),
2388 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002389 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002390 break;
2391
2392 default:
2393 LOG(FATAL) << "Unexpected type conversion from " << input_type
2394 << " to " << result_type;
2395 }
2396 break;
2397
Roland Levillain981e4542014-11-14 11:47:14 +00002398 case Primitive::kPrimChar:
2399 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002400 case Primitive::kPrimLong:
2401 // Type conversion from long to char is a result of code transformations.
2402 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2403 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002404 case Primitive::kPrimBoolean:
2405 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002406 case Primitive::kPrimByte:
2407 case Primitive::kPrimShort:
2408 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002409 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002410 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002411 break;
2412
2413 default:
2414 LOG(FATAL) << "Unexpected type conversion from " << input_type
2415 << " to " << result_type;
2416 }
2417 break;
2418
Roland Levillaindff1f282014-11-05 14:15:05 +00002419 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002420 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002421 case Primitive::kPrimBoolean:
2422 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002423 case Primitive::kPrimByte:
2424 case Primitive::kPrimShort:
2425 case Primitive::kPrimInt:
2426 case Primitive::kPrimChar: {
2427 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002428 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2429 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002430 break;
2431 }
2432
Roland Levillain5b3ee562015-04-14 16:02:41 +01002433 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002434 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002435 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2436 conversion,
2437 conversion->GetDexPc(),
2438 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002439 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002440 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002441
Roland Levillaincff13742014-11-17 14:32:17 +00002442 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002443 // Processing a Dex `double-to-float' instruction.
2444 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2445 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002446 break;
2447
2448 default:
2449 LOG(FATAL) << "Unexpected type conversion from " << input_type
2450 << " to " << result_type;
2451 };
2452 break;
2453
Roland Levillaindff1f282014-11-05 14:15:05 +00002454 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002455 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002456 case Primitive::kPrimBoolean:
2457 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002458 case Primitive::kPrimByte:
2459 case Primitive::kPrimShort:
2460 case Primitive::kPrimInt:
2461 case Primitive::kPrimChar: {
2462 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002463 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002464 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2465 out.AsFpuRegisterPairLow<SRegister>());
2466 break;
2467 }
2468
Roland Levillain647b9ed2014-11-27 12:06:00 +00002469 case Primitive::kPrimLong: {
2470 // Processing a Dex `long-to-double' instruction.
2471 Register low = in.AsRegisterPairLow<Register>();
2472 Register high = in.AsRegisterPairHigh<Register>();
2473 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2474 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002475 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002476 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002477 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2478 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002479
Roland Levillain682393c2015-04-14 15:57:52 +01002480 // temp_d = int-to-double(high)
2481 __ vmovsr(temp_s, high);
2482 __ vcvtdi(temp_d, temp_s);
2483 // constant_d = k2Pow32EncodingForDouble
2484 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2485 // out_d = unsigned-to-double(low)
2486 __ vmovsr(out_s, low);
2487 __ vcvtdu(out_d, out_s);
2488 // out_d += temp_d * constant_d
2489 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002490 break;
2491 }
2492
Roland Levillaincff13742014-11-17 14:32:17 +00002493 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002494 // Processing a Dex `float-to-double' instruction.
2495 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2496 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002497 break;
2498
2499 default:
2500 LOG(FATAL) << "Unexpected type conversion from " << input_type
2501 << " to " << result_type;
2502 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002503 break;
2504
2505 default:
2506 LOG(FATAL) << "Unexpected type conversion from " << input_type
2507 << " to " << result_type;
2508 }
2509}
2510
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002511void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002512 LocationSummary* locations =
2513 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002514 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002515 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002516 locations->SetInAt(0, Location::RequiresRegister());
2517 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002518 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2519 break;
2520 }
2521
2522 case Primitive::kPrimLong: {
2523 locations->SetInAt(0, Location::RequiresRegister());
2524 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002525 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002526 break;
2527 }
2528
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002529 case Primitive::kPrimFloat:
2530 case Primitive::kPrimDouble: {
2531 locations->SetInAt(0, Location::RequiresFpuRegister());
2532 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002533 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002534 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002535 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002536
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002537 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002538 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002539 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002540}
2541
2542void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2543 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002544 Location out = locations->Out();
2545 Location first = locations->InAt(0);
2546 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002547 switch (add->GetResultType()) {
2548 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002549 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002550 __ add(out.AsRegister<Register>(),
2551 first.AsRegister<Register>(),
2552 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002553 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002554 __ AddConstant(out.AsRegister<Register>(),
2555 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002556 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002557 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002558 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002559
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002560 case Primitive::kPrimLong: {
2561 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002562 __ adds(out.AsRegisterPairLow<Register>(),
2563 first.AsRegisterPairLow<Register>(),
2564 ShifterOperand(second.AsRegisterPairLow<Register>()));
2565 __ adc(out.AsRegisterPairHigh<Register>(),
2566 first.AsRegisterPairHigh<Register>(),
2567 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002568 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002569 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002570
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002571 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002572 __ vadds(out.AsFpuRegister<SRegister>(),
2573 first.AsFpuRegister<SRegister>(),
2574 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002575 break;
2576
2577 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002578 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2579 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2580 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002581 break;
2582
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002583 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002584 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002585 }
2586}
2587
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002588void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002589 LocationSummary* locations =
2590 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002591 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002592 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002593 locations->SetInAt(0, Location::RequiresRegister());
2594 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002595 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2596 break;
2597 }
2598
2599 case Primitive::kPrimLong: {
2600 locations->SetInAt(0, Location::RequiresRegister());
2601 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002602 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002603 break;
2604 }
Calin Juravle11351682014-10-23 15:38:15 +01002605 case Primitive::kPrimFloat:
2606 case Primitive::kPrimDouble: {
2607 locations->SetInAt(0, Location::RequiresFpuRegister());
2608 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002609 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002610 break;
Calin Juravle11351682014-10-23 15:38:15 +01002611 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002612 default:
Calin Juravle11351682014-10-23 15:38:15 +01002613 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002614 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002615}
2616
2617void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2618 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002619 Location out = locations->Out();
2620 Location first = locations->InAt(0);
2621 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002622 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002623 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002624 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002625 __ sub(out.AsRegister<Register>(),
2626 first.AsRegister<Register>(),
2627 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002628 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002629 __ AddConstant(out.AsRegister<Register>(),
2630 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002631 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002632 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002633 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002634 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002635
Calin Juravle11351682014-10-23 15:38:15 +01002636 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002637 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002638 __ subs(out.AsRegisterPairLow<Register>(),
2639 first.AsRegisterPairLow<Register>(),
2640 ShifterOperand(second.AsRegisterPairLow<Register>()));
2641 __ sbc(out.AsRegisterPairHigh<Register>(),
2642 first.AsRegisterPairHigh<Register>(),
2643 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002644 break;
Calin Juravle11351682014-10-23 15:38:15 +01002645 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002646
Calin Juravle11351682014-10-23 15:38:15 +01002647 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002648 __ vsubs(out.AsFpuRegister<SRegister>(),
2649 first.AsFpuRegister<SRegister>(),
2650 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002651 break;
Calin Juravle11351682014-10-23 15:38:15 +01002652 }
2653
2654 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002655 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2656 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2657 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002658 break;
2659 }
2660
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002661
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002662 default:
Calin Juravle11351682014-10-23 15:38:15 +01002663 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002664 }
2665}
2666
Calin Juravle34bacdf2014-10-07 20:23:36 +01002667void LocationsBuilderARM::VisitMul(HMul* mul) {
2668 LocationSummary* locations =
2669 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2670 switch (mul->GetResultType()) {
2671 case Primitive::kPrimInt:
2672 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002673 locations->SetInAt(0, Location::RequiresRegister());
2674 locations->SetInAt(1, Location::RequiresRegister());
2675 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002676 break;
2677 }
2678
Calin Juravleb5bfa962014-10-21 18:02:24 +01002679 case Primitive::kPrimFloat:
2680 case Primitive::kPrimDouble: {
2681 locations->SetInAt(0, Location::RequiresFpuRegister());
2682 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002683 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002684 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002685 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002686
2687 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002688 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002689 }
2690}
2691
2692void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2693 LocationSummary* locations = mul->GetLocations();
2694 Location out = locations->Out();
2695 Location first = locations->InAt(0);
2696 Location second = locations->InAt(1);
2697 switch (mul->GetResultType()) {
2698 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002699 __ mul(out.AsRegister<Register>(),
2700 first.AsRegister<Register>(),
2701 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002702 break;
2703 }
2704 case Primitive::kPrimLong: {
2705 Register out_hi = out.AsRegisterPairHigh<Register>();
2706 Register out_lo = out.AsRegisterPairLow<Register>();
2707 Register in1_hi = first.AsRegisterPairHigh<Register>();
2708 Register in1_lo = first.AsRegisterPairLow<Register>();
2709 Register in2_hi = second.AsRegisterPairHigh<Register>();
2710 Register in2_lo = second.AsRegisterPairLow<Register>();
2711
2712 // Extra checks to protect caused by the existence of R1_R2.
2713 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2714 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2715 DCHECK_NE(out_hi, in1_lo);
2716 DCHECK_NE(out_hi, in2_lo);
2717
2718 // input: in1 - 64 bits, in2 - 64 bits
2719 // output: out
2720 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2721 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2722 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2723
2724 // IP <- in1.lo * in2.hi
2725 __ mul(IP, in1_lo, in2_hi);
2726 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2727 __ mla(out_hi, in1_hi, in2_lo, IP);
2728 // out.lo <- (in1.lo * in2.lo)[31:0];
2729 __ umull(out_lo, IP, in1_lo, in2_lo);
2730 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2731 __ add(out_hi, out_hi, ShifterOperand(IP));
2732 break;
2733 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002734
2735 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002736 __ vmuls(out.AsFpuRegister<SRegister>(),
2737 first.AsFpuRegister<SRegister>(),
2738 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002739 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002740 }
2741
2742 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002743 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2744 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2745 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002746 break;
2747 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002748
2749 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002750 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002751 }
2752}
2753
Zheng Xuc6667102015-05-15 16:08:45 +08002754void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2755 DCHECK(instruction->IsDiv() || instruction->IsRem());
2756 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2757
2758 LocationSummary* locations = instruction->GetLocations();
2759 Location second = locations->InAt(1);
2760 DCHECK(second.IsConstant());
2761
2762 Register out = locations->Out().AsRegister<Register>();
2763 Register dividend = locations->InAt(0).AsRegister<Register>();
2764 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2765 DCHECK(imm == 1 || imm == -1);
2766
2767 if (instruction->IsRem()) {
2768 __ LoadImmediate(out, 0);
2769 } else {
2770 if (imm == 1) {
2771 __ Mov(out, dividend);
2772 } else {
2773 __ rsb(out, dividend, ShifterOperand(0));
2774 }
2775 }
2776}
2777
2778void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2779 DCHECK(instruction->IsDiv() || instruction->IsRem());
2780 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2781
2782 LocationSummary* locations = instruction->GetLocations();
2783 Location second = locations->InAt(1);
2784 DCHECK(second.IsConstant());
2785
2786 Register out = locations->Out().AsRegister<Register>();
2787 Register dividend = locations->InAt(0).AsRegister<Register>();
2788 Register temp = locations->GetTemp(0).AsRegister<Register>();
2789 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002790 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002791 int ctz_imm = CTZ(abs_imm);
2792
2793 if (ctz_imm == 1) {
2794 __ Lsr(temp, dividend, 32 - ctz_imm);
2795 } else {
2796 __ Asr(temp, dividend, 31);
2797 __ Lsr(temp, temp, 32 - ctz_imm);
2798 }
2799 __ add(out, temp, ShifterOperand(dividend));
2800
2801 if (instruction->IsDiv()) {
2802 __ Asr(out, out, ctz_imm);
2803 if (imm < 0) {
2804 __ rsb(out, out, ShifterOperand(0));
2805 }
2806 } else {
2807 __ ubfx(out, out, 0, ctz_imm);
2808 __ sub(out, out, ShifterOperand(temp));
2809 }
2810}
2811
2812void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2813 DCHECK(instruction->IsDiv() || instruction->IsRem());
2814 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2815
2816 LocationSummary* locations = instruction->GetLocations();
2817 Location second = locations->InAt(1);
2818 DCHECK(second.IsConstant());
2819
2820 Register out = locations->Out().AsRegister<Register>();
2821 Register dividend = locations->InAt(0).AsRegister<Register>();
2822 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2823 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2824 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2825
2826 int64_t magic;
2827 int shift;
2828 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2829
2830 __ LoadImmediate(temp1, magic);
2831 __ smull(temp2, temp1, dividend, temp1);
2832
2833 if (imm > 0 && magic < 0) {
2834 __ add(temp1, temp1, ShifterOperand(dividend));
2835 } else if (imm < 0 && magic > 0) {
2836 __ sub(temp1, temp1, ShifterOperand(dividend));
2837 }
2838
2839 if (shift != 0) {
2840 __ Asr(temp1, temp1, shift);
2841 }
2842
2843 if (instruction->IsDiv()) {
2844 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2845 } else {
2846 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2847 // TODO: Strength reduction for mls.
2848 __ LoadImmediate(temp2, imm);
2849 __ mls(out, temp1, temp2, dividend);
2850 }
2851}
2852
2853void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2854 DCHECK(instruction->IsDiv() || instruction->IsRem());
2855 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2856
2857 LocationSummary* locations = instruction->GetLocations();
2858 Location second = locations->InAt(1);
2859 DCHECK(second.IsConstant());
2860
2861 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2862 if (imm == 0) {
2863 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2864 } else if (imm == 1 || imm == -1) {
2865 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002866 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002867 DivRemByPowerOfTwo(instruction);
2868 } else {
2869 DCHECK(imm <= -2 || imm >= 2);
2870 GenerateDivRemWithAnyConstant(instruction);
2871 }
2872}
2873
Calin Juravle7c4954d2014-10-28 16:57:40 +00002874void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002875 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2876 if (div->GetResultType() == Primitive::kPrimLong) {
2877 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002878 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08002879 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2880 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002881 } else if (div->GetResultType() == Primitive::kPrimInt &&
2882 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2883 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002884 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002885 }
2886
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002887 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2888
Calin Juravle7c4954d2014-10-28 16:57:40 +00002889 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002890 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002891 if (div->InputAt(1)->IsConstant()) {
2892 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002893 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002895 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
2896 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002897 // No temp register required.
2898 } else {
2899 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002900 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002901 locations->AddTemp(Location::RequiresRegister());
2902 }
2903 }
2904 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002905 locations->SetInAt(0, Location::RequiresRegister());
2906 locations->SetInAt(1, Location::RequiresRegister());
2907 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2908 } else {
2909 InvokeRuntimeCallingConvention calling_convention;
2910 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2911 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2912 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2913 // we only need the former.
2914 locations->SetOut(Location::RegisterLocation(R0));
2915 }
Calin Juravled0d48522014-11-04 16:40:20 +00002916 break;
2917 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002918 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002919 InvokeRuntimeCallingConvention calling_convention;
2920 locations->SetInAt(0, Location::RegisterPairLocation(
2921 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2922 locations->SetInAt(1, Location::RegisterPairLocation(
2923 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002924 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002925 break;
2926 }
2927 case Primitive::kPrimFloat:
2928 case Primitive::kPrimDouble: {
2929 locations->SetInAt(0, Location::RequiresFpuRegister());
2930 locations->SetInAt(1, Location::RequiresFpuRegister());
2931 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2932 break;
2933 }
2934
2935 default:
2936 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2937 }
2938}
2939
2940void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2941 LocationSummary* locations = div->GetLocations();
2942 Location out = locations->Out();
2943 Location first = locations->InAt(0);
2944 Location second = locations->InAt(1);
2945
2946 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002947 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002948 if (second.IsConstant()) {
2949 GenerateDivRemConstantIntegral(div);
2950 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002951 __ sdiv(out.AsRegister<Register>(),
2952 first.AsRegister<Register>(),
2953 second.AsRegister<Register>());
2954 } else {
2955 InvokeRuntimeCallingConvention calling_convention;
2956 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2957 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2958 DCHECK_EQ(R0, out.AsRegister<Register>());
2959
2960 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002961 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002962 }
Calin Juravled0d48522014-11-04 16:40:20 +00002963 break;
2964 }
2965
Calin Juravle7c4954d2014-10-28 16:57:40 +00002966 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002967 InvokeRuntimeCallingConvention calling_convention;
2968 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2969 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2970 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2971 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2972 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002973 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002974
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002975 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002976 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002977 break;
2978 }
2979
2980 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002981 __ vdivs(out.AsFpuRegister<SRegister>(),
2982 first.AsFpuRegister<SRegister>(),
2983 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002984 break;
2985 }
2986
2987 case Primitive::kPrimDouble: {
2988 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2989 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2990 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2991 break;
2992 }
2993
2994 default:
2995 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2996 }
2997}
2998
Calin Juravlebacfec32014-11-14 15:54:36 +00002999void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003000 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003001
3002 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003003 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08003004 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3005 // sdiv will be replaced by other instruction sequence.
3006 call_kind = LocationSummary::kNoCall;
3007 } else if ((rem->GetResultType() == Primitive::kPrimInt)
3008 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003009 // Have hardware divide instruction for int, do it with three instructions.
3010 call_kind = LocationSummary::kNoCall;
3011 }
3012
Calin Juravlebacfec32014-11-14 15:54:36 +00003013 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3014
Calin Juravled2ec87d2014-12-08 14:24:46 +00003015 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003016 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003017 if (rem->InputAt(1)->IsConstant()) {
3018 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003019 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003020 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003021 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
3022 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08003023 // No temp register required.
3024 } else {
3025 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003026 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08003027 locations->AddTemp(Location::RequiresRegister());
3028 }
3029 }
3030 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003031 locations->SetInAt(0, Location::RequiresRegister());
3032 locations->SetInAt(1, Location::RequiresRegister());
3033 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3034 locations->AddTemp(Location::RequiresRegister());
3035 } else {
3036 InvokeRuntimeCallingConvention calling_convention;
3037 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3038 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3039 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3040 // we only need the latter.
3041 locations->SetOut(Location::RegisterLocation(R1));
3042 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003043 break;
3044 }
3045 case Primitive::kPrimLong: {
3046 InvokeRuntimeCallingConvention calling_convention;
3047 locations->SetInAt(0, Location::RegisterPairLocation(
3048 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3049 locations->SetInAt(1, Location::RegisterPairLocation(
3050 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3051 // The runtime helper puts the output in R2,R3.
3052 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3053 break;
3054 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003055 case Primitive::kPrimFloat: {
3056 InvokeRuntimeCallingConvention calling_convention;
3057 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3058 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3059 locations->SetOut(Location::FpuRegisterLocation(S0));
3060 break;
3061 }
3062
Calin Juravlebacfec32014-11-14 15:54:36 +00003063 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003064 InvokeRuntimeCallingConvention calling_convention;
3065 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3066 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3067 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3068 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3069 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003070 break;
3071 }
3072
3073 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003074 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003075 }
3076}
3077
3078void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3079 LocationSummary* locations = rem->GetLocations();
3080 Location out = locations->Out();
3081 Location first = locations->InAt(0);
3082 Location second = locations->InAt(1);
3083
Calin Juravled2ec87d2014-12-08 14:24:46 +00003084 Primitive::Type type = rem->GetResultType();
3085 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003086 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003087 if (second.IsConstant()) {
3088 GenerateDivRemConstantIntegral(rem);
3089 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003090 Register reg1 = first.AsRegister<Register>();
3091 Register reg2 = second.AsRegister<Register>();
3092 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003093
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003094 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003095 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003096 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003097 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003098 } else {
3099 InvokeRuntimeCallingConvention calling_convention;
3100 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3101 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3102 DCHECK_EQ(R1, out.AsRegister<Register>());
3103
3104 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003105 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003106 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003107 break;
3108 }
3109
3110 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003111 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003112 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003113 break;
3114 }
3115
Calin Juravled2ec87d2014-12-08 14:24:46 +00003116 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003117 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003118 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003119 break;
3120 }
3121
Calin Juravlebacfec32014-11-14 15:54:36 +00003122 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003123 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003124 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003125 break;
3126 }
3127
3128 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003129 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003130 }
3131}
3132
Calin Juravled0d48522014-11-04 16:40:20 +00003133void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003134 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3135 ? LocationSummary::kCallOnSlowPath
3136 : LocationSummary::kNoCall;
3137 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003138 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003139 if (instruction->HasUses()) {
3140 locations->SetOut(Location::SameAsFirstInput());
3141 }
3142}
3143
3144void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003145 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003146 codegen_->AddSlowPath(slow_path);
3147
3148 LocationSummary* locations = instruction->GetLocations();
3149 Location value = locations->InAt(0);
3150
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003151 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003152 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003153 case Primitive::kPrimByte:
3154 case Primitive::kPrimChar:
3155 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003156 case Primitive::kPrimInt: {
3157 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003158 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003159 } else {
3160 DCHECK(value.IsConstant()) << value;
3161 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3162 __ b(slow_path->GetEntryLabel());
3163 }
3164 }
3165 break;
3166 }
3167 case Primitive::kPrimLong: {
3168 if (value.IsRegisterPair()) {
3169 __ orrs(IP,
3170 value.AsRegisterPairLow<Register>(),
3171 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3172 __ b(slow_path->GetEntryLabel(), EQ);
3173 } else {
3174 DCHECK(value.IsConstant()) << value;
3175 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3176 __ b(slow_path->GetEntryLabel());
3177 }
3178 }
3179 break;
3180 default:
3181 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3182 }
3183 }
Calin Juravled0d48522014-11-04 16:40:20 +00003184}
3185
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003186void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3187 Register in = locations->InAt(0).AsRegister<Register>();
3188 Location rhs = locations->InAt(1);
3189 Register out = locations->Out().AsRegister<Register>();
3190
3191 if (rhs.IsConstant()) {
3192 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3193 // so map all rotations to a +ve. equivalent in that range.
3194 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3195 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3196 if (rot) {
3197 // Rotate, mapping left rotations to right equivalents if necessary.
3198 // (e.g. left by 2 bits == right by 30.)
3199 __ Ror(out, in, rot);
3200 } else if (out != in) {
3201 __ Mov(out, in);
3202 }
3203 } else {
3204 __ Ror(out, in, rhs.AsRegister<Register>());
3205 }
3206}
3207
3208// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3209// rotates by swapping input regs (effectively rotating by the first 32-bits of
3210// a larger rotation) or flipping direction (thus treating larger right/left
3211// rotations as sub-word sized rotations in the other direction) as appropriate.
3212void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3213 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3214 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3215 Location rhs = locations->InAt(1);
3216 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3217 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3218
3219 if (rhs.IsConstant()) {
3220 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3221 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003222 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003223 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3224 // logic below to a simple pair of binary orr.
3225 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3226 if (rot >= kArmBitsPerWord) {
3227 rot -= kArmBitsPerWord;
3228 std::swap(in_reg_hi, in_reg_lo);
3229 }
3230 // Rotate, or mov to out for zero or word size rotations.
3231 if (rot != 0u) {
3232 __ Lsr(out_reg_hi, in_reg_hi, rot);
3233 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3234 __ Lsr(out_reg_lo, in_reg_lo, rot);
3235 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3236 } else {
3237 __ Mov(out_reg_lo, in_reg_lo);
3238 __ Mov(out_reg_hi, in_reg_hi);
3239 }
3240 } else {
3241 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3242 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3243 Label end;
3244 Label shift_by_32_plus_shift_right;
3245
3246 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3247 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3248 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3249 __ b(&shift_by_32_plus_shift_right, CC);
3250
3251 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3252 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3253 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3254 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3255 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3256 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3257 __ Lsr(shift_left, in_reg_hi, shift_right);
3258 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3259 __ b(&end);
3260
3261 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3262 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3263 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3264 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3265 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3266 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3267 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3268 __ Lsl(shift_right, in_reg_hi, shift_left);
3269 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3270
3271 __ Bind(&end);
3272 }
3273}
Roland Levillain22c49222016-03-18 14:04:28 +00003274
3275void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003276 LocationSummary* locations =
3277 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3278 switch (ror->GetResultType()) {
3279 case Primitive::kPrimInt: {
3280 locations->SetInAt(0, Location::RequiresRegister());
3281 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3282 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3283 break;
3284 }
3285 case Primitive::kPrimLong: {
3286 locations->SetInAt(0, Location::RequiresRegister());
3287 if (ror->InputAt(1)->IsConstant()) {
3288 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3289 } else {
3290 locations->SetInAt(1, Location::RequiresRegister());
3291 locations->AddTemp(Location::RequiresRegister());
3292 locations->AddTemp(Location::RequiresRegister());
3293 }
3294 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3295 break;
3296 }
3297 default:
3298 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3299 }
3300}
3301
Roland Levillain22c49222016-03-18 14:04:28 +00003302void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003303 LocationSummary* locations = ror->GetLocations();
3304 Primitive::Type type = ror->GetResultType();
3305 switch (type) {
3306 case Primitive::kPrimInt: {
3307 HandleIntegerRotate(locations);
3308 break;
3309 }
3310 case Primitive::kPrimLong: {
3311 HandleLongRotate(locations);
3312 break;
3313 }
3314 default:
3315 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003316 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003317 }
3318}
3319
Calin Juravle9aec02f2014-11-18 23:06:35 +00003320void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3321 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3322
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003323 LocationSummary* locations =
3324 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003325
3326 switch (op->GetResultType()) {
3327 case Primitive::kPrimInt: {
3328 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003329 if (op->InputAt(1)->IsConstant()) {
3330 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3331 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3332 } else {
3333 locations->SetInAt(1, Location::RequiresRegister());
3334 // Make the output overlap, as it will be used to hold the masked
3335 // second input.
3336 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3337 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003338 break;
3339 }
3340 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003341 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003342 if (op->InputAt(1)->IsConstant()) {
3343 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3344 // For simplicity, use kOutputOverlap even though we only require that low registers
3345 // don't clash with high registers which the register allocator currently guarantees.
3346 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3347 } else {
3348 locations->SetInAt(1, Location::RequiresRegister());
3349 locations->AddTemp(Location::RequiresRegister());
3350 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3351 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003352 break;
3353 }
3354 default:
3355 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3356 }
3357}
3358
3359void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3360 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3361
3362 LocationSummary* locations = op->GetLocations();
3363 Location out = locations->Out();
3364 Location first = locations->InAt(0);
3365 Location second = locations->InAt(1);
3366
3367 Primitive::Type type = op->GetResultType();
3368 switch (type) {
3369 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003370 Register out_reg = out.AsRegister<Register>();
3371 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003372 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003373 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003374 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003375 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003376 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003377 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003378 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003379 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003380 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003381 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003382 }
3383 } else {
3384 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003385 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003386 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003387 __ Mov(out_reg, first_reg);
3388 } else if (op->IsShl()) {
3389 __ Lsl(out_reg, first_reg, shift_value);
3390 } else if (op->IsShr()) {
3391 __ Asr(out_reg, first_reg, shift_value);
3392 } else {
3393 __ Lsr(out_reg, first_reg, shift_value);
3394 }
3395 }
3396 break;
3397 }
3398 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003399 Register o_h = out.AsRegisterPairHigh<Register>();
3400 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003401
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003402 Register high = first.AsRegisterPairHigh<Register>();
3403 Register low = first.AsRegisterPairLow<Register>();
3404
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003405 if (second.IsRegister()) {
3406 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003407
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003408 Register second_reg = second.AsRegister<Register>();
3409
3410 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003411 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003412 // Shift the high part
3413 __ Lsl(o_h, high, o_l);
3414 // Shift the low part and `or` what overflew on the high part
3415 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3416 __ Lsr(temp, low, temp);
3417 __ orr(o_h, o_h, ShifterOperand(temp));
3418 // If the shift is > 32 bits, override the high part
3419 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3420 __ it(PL);
3421 __ Lsl(o_h, low, temp, PL);
3422 // Shift the low part
3423 __ Lsl(o_l, low, o_l);
3424 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003425 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003426 // Shift the low part
3427 __ Lsr(o_l, low, o_h);
3428 // Shift the high part and `or` what underflew on the low part
3429 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3430 __ Lsl(temp, high, temp);
3431 __ orr(o_l, o_l, ShifterOperand(temp));
3432 // If the shift is > 32 bits, override the low part
3433 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3434 __ it(PL);
3435 __ Asr(o_l, high, temp, PL);
3436 // Shift the high part
3437 __ Asr(o_h, high, o_h);
3438 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003439 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003440 // same as Shr except we use `Lsr`s and not `Asr`s
3441 __ Lsr(o_l, low, o_h);
3442 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3443 __ Lsl(temp, high, temp);
3444 __ orr(o_l, o_l, ShifterOperand(temp));
3445 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3446 __ it(PL);
3447 __ Lsr(o_l, high, temp, PL);
3448 __ Lsr(o_h, high, o_h);
3449 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003450 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003451 // Register allocator doesn't create partial overlap.
3452 DCHECK_NE(o_l, high);
3453 DCHECK_NE(o_h, low);
3454 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003455 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003456 if (shift_value > 32) {
3457 if (op->IsShl()) {
3458 __ Lsl(o_h, low, shift_value - 32);
3459 __ LoadImmediate(o_l, 0);
3460 } else if (op->IsShr()) {
3461 __ Asr(o_l, high, shift_value - 32);
3462 __ Asr(o_h, high, 31);
3463 } else {
3464 __ Lsr(o_l, high, shift_value - 32);
3465 __ LoadImmediate(o_h, 0);
3466 }
3467 } else if (shift_value == 32) {
3468 if (op->IsShl()) {
3469 __ mov(o_h, ShifterOperand(low));
3470 __ LoadImmediate(o_l, 0);
3471 } else if (op->IsShr()) {
3472 __ mov(o_l, ShifterOperand(high));
3473 __ Asr(o_h, high, 31);
3474 } else {
3475 __ mov(o_l, ShifterOperand(high));
3476 __ LoadImmediate(o_h, 0);
3477 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003478 } else if (shift_value == 1) {
3479 if (op->IsShl()) {
3480 __ Lsls(o_l, low, 1);
3481 __ adc(o_h, high, ShifterOperand(high));
3482 } else if (op->IsShr()) {
3483 __ Asrs(o_h, high, 1);
3484 __ Rrx(o_l, low);
3485 } else {
3486 __ Lsrs(o_h, high, 1);
3487 __ Rrx(o_l, low);
3488 }
3489 } else {
3490 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003491 if (op->IsShl()) {
3492 __ Lsl(o_h, high, shift_value);
3493 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3494 __ Lsl(o_l, low, shift_value);
3495 } else if (op->IsShr()) {
3496 __ Lsr(o_l, low, shift_value);
3497 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3498 __ Asr(o_h, high, shift_value);
3499 } else {
3500 __ Lsr(o_l, low, shift_value);
3501 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3502 __ Lsr(o_h, high, shift_value);
3503 }
3504 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003505 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003506 break;
3507 }
3508 default:
3509 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003510 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003511 }
3512}
3513
3514void LocationsBuilderARM::VisitShl(HShl* shl) {
3515 HandleShift(shl);
3516}
3517
3518void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3519 HandleShift(shl);
3520}
3521
3522void LocationsBuilderARM::VisitShr(HShr* shr) {
3523 HandleShift(shr);
3524}
3525
3526void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3527 HandleShift(shr);
3528}
3529
3530void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3531 HandleShift(ushr);
3532}
3533
3534void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3535 HandleShift(ushr);
3536}
3537
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003538void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003539 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003540 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00003541 if (instruction->IsStringAlloc()) {
3542 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3543 } else {
3544 InvokeRuntimeCallingConvention calling_convention;
3545 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3546 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3547 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003548 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003549}
3550
3551void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003552 // Note: if heap poisoning is enabled, the entry point takes cares
3553 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003554 if (instruction->IsStringAlloc()) {
3555 // String is allocated through StringFactory. Call NewEmptyString entry point.
3556 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07003557 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00003558 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3559 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3560 __ blx(LR);
3561 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3562 } else {
3563 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3564 instruction,
3565 instruction->GetDexPc(),
3566 nullptr);
3567 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3568 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003569}
3570
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003571void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3572 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003573 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003574 InvokeRuntimeCallingConvention calling_convention;
3575 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003576 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003577 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003578 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003579}
3580
3581void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3582 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003583 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003584 // Note: if heap poisoning is enabled, the entry point takes cares
3585 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003586 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003587 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003588 instruction->GetDexPc(),
3589 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003590 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003591}
3592
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003593void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003594 LocationSummary* locations =
3595 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003596 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3597 if (location.IsStackSlot()) {
3598 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3599 } else if (location.IsDoubleStackSlot()) {
3600 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003601 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003602 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003603}
3604
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003605void InstructionCodeGeneratorARM::VisitParameterValue(
3606 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003607 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003608}
3609
3610void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3611 LocationSummary* locations =
3612 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3613 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3614}
3615
3616void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3617 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003618}
3619
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003620void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003621 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003622 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003623 locations->SetInAt(0, Location::RequiresRegister());
3624 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003625}
3626
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003627void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3628 LocationSummary* locations = not_->GetLocations();
3629 Location out = locations->Out();
3630 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003631 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003632 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003633 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003634 break;
3635
3636 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003637 __ mvn(out.AsRegisterPairLow<Register>(),
3638 ShifterOperand(in.AsRegisterPairLow<Register>()));
3639 __ mvn(out.AsRegisterPairHigh<Register>(),
3640 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003641 break;
3642
3643 default:
3644 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3645 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003646}
3647
David Brazdil66d126e2015-04-03 16:02:44 +01003648void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3649 LocationSummary* locations =
3650 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3651 locations->SetInAt(0, Location::RequiresRegister());
3652 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3653}
3654
3655void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003656 LocationSummary* locations = bool_not->GetLocations();
3657 Location out = locations->Out();
3658 Location in = locations->InAt(0);
3659 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3660}
3661
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003662void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003663 LocationSummary* locations =
3664 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003665 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003666 case Primitive::kPrimBoolean:
3667 case Primitive::kPrimByte:
3668 case Primitive::kPrimShort:
3669 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003670 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00003671 case Primitive::kPrimLong: {
3672 locations->SetInAt(0, Location::RequiresRegister());
3673 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003674 // Output overlaps because it is written before doing the low comparison.
3675 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003676 break;
3677 }
3678 case Primitive::kPrimFloat:
3679 case Primitive::kPrimDouble: {
3680 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01003681 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00003682 locations->SetOut(Location::RequiresRegister());
3683 break;
3684 }
3685 default:
3686 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3687 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003688}
3689
3690void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003691 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003692 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003693 Location left = locations->InAt(0);
3694 Location right = locations->InAt(1);
3695
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003696 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003697 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00003698 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00003699 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003700 case Primitive::kPrimBoolean:
3701 case Primitive::kPrimByte:
3702 case Primitive::kPrimShort:
3703 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003704 case Primitive::kPrimInt: {
3705 __ LoadImmediate(out, 0);
3706 __ cmp(left.AsRegister<Register>(),
3707 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
3708 less_cond = LT;
3709 break;
3710 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003711 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003712 __ cmp(left.AsRegisterPairHigh<Register>(),
3713 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003714 __ b(&less, LT);
3715 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003716 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003717 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003718 __ cmp(left.AsRegisterPairLow<Register>(),
3719 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003720 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00003721 break;
3722 }
3723 case Primitive::kPrimFloat:
3724 case Primitive::kPrimDouble: {
3725 __ LoadImmediate(out, 0);
Vladimir Marko37dd80d2016-08-01 17:41:45 +01003726 GenerateVcmp(compare);
Calin Juravleddb7df22014-11-25 20:56:51 +00003727 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003728 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003729 break;
3730 }
3731 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003732 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00003733 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003734 }
Aart Bika19616e2016-02-01 18:57:58 -08003735
Calin Juravleddb7df22014-11-25 20:56:51 +00003736 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00003737 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00003738
3739 __ Bind(&greater);
3740 __ LoadImmediate(out, 1);
3741 __ b(&done);
3742
3743 __ Bind(&less);
3744 __ LoadImmediate(out, -1);
3745
3746 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003747}
3748
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003749void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003750 LocationSummary* locations =
3751 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01003752 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003753 locations->SetInAt(i, Location::Any());
3754 }
3755 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003756}
3757
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003758void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003759 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003760}
3761
Roland Levillainc9285912015-12-18 10:38:42 +00003762void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3763 // TODO (ported from quick): revisit ARM barrier kinds.
3764 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00003765 switch (kind) {
3766 case MemBarrierKind::kAnyStore:
3767 case MemBarrierKind::kLoadAny:
3768 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003769 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003770 break;
3771 }
3772 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003773 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003774 break;
3775 }
3776 default:
3777 LOG(FATAL) << "Unexpected memory barrier " << kind;
3778 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003779 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003780}
3781
3782void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3783 uint32_t offset,
3784 Register out_lo,
3785 Register out_hi) {
3786 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003787 // Ensure `out_lo` is different from `addr`, so that loading
3788 // `offset` into `out_lo` does not clutter `addr`.
3789 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003790 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003791 __ add(IP, addr, ShifterOperand(out_lo));
3792 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003793 }
3794 __ ldrexd(out_lo, out_hi, addr);
3795}
3796
3797void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3798 uint32_t offset,
3799 Register value_lo,
3800 Register value_hi,
3801 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003802 Register temp2,
3803 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003804 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003805 if (offset != 0) {
3806 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003807 __ add(IP, addr, ShifterOperand(temp1));
3808 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003809 }
3810 __ Bind(&fail);
3811 // We need a load followed by store. (The address used in a STREX instruction must
3812 // be the same as the address in the most recently executed LDREX instruction.)
3813 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003814 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003815 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003816 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003817}
3818
3819void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3820 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3821
Nicolas Geoffray39468442014-09-02 15:17:15 +01003822 LocationSummary* locations =
3823 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003824 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003825
Calin Juravle52c48962014-12-16 17:02:57 +00003826 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003827 if (Primitive::IsFloatingPointType(field_type)) {
3828 locations->SetInAt(1, Location::RequiresFpuRegister());
3829 } else {
3830 locations->SetInAt(1, Location::RequiresRegister());
3831 }
3832
Calin Juravle52c48962014-12-16 17:02:57 +00003833 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003834 bool generate_volatile = field_info.IsVolatile()
3835 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003836 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003837 bool needs_write_barrier =
3838 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003839 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003840 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003841 if (needs_write_barrier) {
3842 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003843 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003844 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003845 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003846 // - registers need to be consecutive
3847 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003848 // We don't test for ARM yet, and the assertion makes sure that we
3849 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003850 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3851
3852 locations->AddTemp(Location::RequiresRegister());
3853 locations->AddTemp(Location::RequiresRegister());
3854 if (field_type == Primitive::kPrimDouble) {
3855 // For doubles we need two more registers to copy the value.
3856 locations->AddTemp(Location::RegisterLocation(R2));
3857 locations->AddTemp(Location::RegisterLocation(R3));
3858 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003859 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003860}
3861
Calin Juravle52c48962014-12-16 17:02:57 +00003862void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003863 const FieldInfo& field_info,
3864 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003865 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3866
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003867 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003868 Register base = locations->InAt(0).AsRegister<Register>();
3869 Location value = locations->InAt(1);
3870
3871 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003872 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003873 Primitive::Type field_type = field_info.GetFieldType();
3874 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003875 bool needs_write_barrier =
3876 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003877
3878 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003879 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00003880 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003881
3882 switch (field_type) {
3883 case Primitive::kPrimBoolean:
3884 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003885 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003886 break;
3887 }
3888
3889 case Primitive::kPrimShort:
3890 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003891 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003892 break;
3893 }
3894
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003895 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003896 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003897 if (kPoisonHeapReferences && needs_write_barrier) {
3898 // Note that in the case where `value` is a null reference,
3899 // we do not enter this block, as a null reference does not
3900 // need poisoning.
3901 DCHECK_EQ(field_type, Primitive::kPrimNot);
3902 Register temp = locations->GetTemp(0).AsRegister<Register>();
3903 __ Mov(temp, value.AsRegister<Register>());
3904 __ PoisonHeapReference(temp);
3905 __ StoreToOffset(kStoreWord, temp, base, offset);
3906 } else {
3907 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3908 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003909 break;
3910 }
3911
3912 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003913 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003914 GenerateWideAtomicStore(base, offset,
3915 value.AsRegisterPairLow<Register>(),
3916 value.AsRegisterPairHigh<Register>(),
3917 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003918 locations->GetTemp(1).AsRegister<Register>(),
3919 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003920 } else {
3921 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003922 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003923 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003924 break;
3925 }
3926
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003927 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003928 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003929 break;
3930 }
3931
3932 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003933 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003934 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003935 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3936 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3937
3938 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3939
3940 GenerateWideAtomicStore(base, offset,
3941 value_reg_lo,
3942 value_reg_hi,
3943 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003944 locations->GetTemp(3).AsRegister<Register>(),
3945 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003946 } else {
3947 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003948 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003949 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003950 break;
3951 }
3952
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003953 case Primitive::kPrimVoid:
3954 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003955 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003956 }
Calin Juravle52c48962014-12-16 17:02:57 +00003957
Calin Juravle77520bc2015-01-12 18:45:46 +00003958 // Longs and doubles are handled in the switch.
3959 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3960 codegen_->MaybeRecordImplicitNullCheck(instruction);
3961 }
3962
3963 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3964 Register temp = locations->GetTemp(0).AsRegister<Register>();
3965 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003966 codegen_->MarkGCCard(
3967 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003968 }
3969
Calin Juravle52c48962014-12-16 17:02:57 +00003970 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003971 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00003972 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003973}
3974
Calin Juravle52c48962014-12-16 17:02:57 +00003975void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3976 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003977
3978 bool object_field_get_with_read_barrier =
3979 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003980 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003981 new (GetGraph()->GetArena()) LocationSummary(instruction,
3982 object_field_get_with_read_barrier ?
3983 LocationSummary::kCallOnSlowPath :
3984 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003985 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003986
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003987 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003988 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003989 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00003990 // The output overlaps in case of volatile long: we don't want the
3991 // code generated by GenerateWideAtomicLoad to overwrite the
3992 // object's location. Likewise, in the case of an object field get
3993 // with read barriers enabled, we do not want the load to overwrite
3994 // the object's location, as we need it to emit the read barrier.
3995 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
3996 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003997
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003998 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3999 locations->SetOut(Location::RequiresFpuRegister());
4000 } else {
4001 locations->SetOut(Location::RequiresRegister(),
4002 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4003 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004004 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00004005 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004006 // - registers need to be consecutive
4007 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004008 // We don't test for ARM yet, and the assertion makes sure that we
4009 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004010 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4011 locations->AddTemp(Location::RequiresRegister());
4012 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00004013 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4014 // We need a temporary register for the read barrier marking slow
4015 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4016 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004017 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004018}
4019
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004020Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
4021 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
4022 << input->GetType();
4023 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
4024 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
4025 return Location::ConstantLocation(input->AsConstant());
4026 } else {
4027 return Location::RequiresFpuRegister();
4028 }
4029}
4030
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004031Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4032 Opcode opcode) {
4033 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4034 if (constant->IsConstant() &&
4035 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4036 return Location::ConstantLocation(constant->AsConstant());
4037 }
4038 return Location::RequiresRegister();
4039}
4040
4041bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4042 Opcode opcode) {
4043 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4044 if (Primitive::Is64BitType(input_cst->GetType())) {
4045 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4046 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4047 } else {
4048 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4049 }
4050}
4051
4052bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4053 ShifterOperand so;
4054 ArmAssembler* assembler = codegen_->GetAssembler();
4055 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4056 return true;
4057 }
4058 Opcode neg_opcode = kNoOperand;
4059 switch (opcode) {
4060 case AND:
4061 neg_opcode = BIC;
4062 break;
4063 case ORR:
4064 neg_opcode = ORN;
4065 break;
4066 default:
4067 return false;
4068 }
4069 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4070}
4071
Calin Juravle52c48962014-12-16 17:02:57 +00004072void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4073 const FieldInfo& field_info) {
4074 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004075
Calin Juravle52c48962014-12-16 17:02:57 +00004076 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004077 Location base_loc = locations->InAt(0);
4078 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004079 Location out = locations->Out();
4080 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004081 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004082 Primitive::Type field_type = field_info.GetFieldType();
4083 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4084
4085 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004086 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004087 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004088 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004089
Roland Levillainc9285912015-12-18 10:38:42 +00004090 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004091 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004092 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004093
Roland Levillainc9285912015-12-18 10:38:42 +00004094 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004095 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004096 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004097
Roland Levillainc9285912015-12-18 10:38:42 +00004098 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004099 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004100 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004101
4102 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004103 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004104 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004105
4106 case Primitive::kPrimNot: {
4107 // /* HeapReference<Object> */ out = *(base + offset)
4108 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4109 Location temp_loc = locations->GetTemp(0);
4110 // Note that a potential implicit null check is handled in this
4111 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4112 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4113 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4114 if (is_volatile) {
4115 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4116 }
4117 } else {
4118 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4119 codegen_->MaybeRecordImplicitNullCheck(instruction);
4120 if (is_volatile) {
4121 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4122 }
4123 // If read barriers are enabled, emit read barriers other than
4124 // Baker's using a slow path (and also unpoison the loaded
4125 // reference, if heap poisoning is enabled).
4126 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4127 }
4128 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004129 }
4130
Roland Levillainc9285912015-12-18 10:38:42 +00004131 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004132 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004133 GenerateWideAtomicLoad(base, offset,
4134 out.AsRegisterPairLow<Register>(),
4135 out.AsRegisterPairHigh<Register>());
4136 } else {
4137 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4138 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004139 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004140
Roland Levillainc9285912015-12-18 10:38:42 +00004141 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004142 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004143 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004144
4145 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004146 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004147 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004148 Register lo = locations->GetTemp(0).AsRegister<Register>();
4149 Register hi = locations->GetTemp(1).AsRegister<Register>();
4150 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004151 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004152 __ vmovdrr(out_reg, lo, hi);
4153 } else {
4154 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004155 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004156 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004157 break;
4158 }
4159
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004160 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004161 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004162 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004163 }
Calin Juravle52c48962014-12-16 17:02:57 +00004164
Roland Levillainc9285912015-12-18 10:38:42 +00004165 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4166 // Potential implicit null checks, in the case of reference or
4167 // double fields, are handled in the previous switch statement.
4168 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004169 codegen_->MaybeRecordImplicitNullCheck(instruction);
4170 }
4171
Calin Juravle52c48962014-12-16 17:02:57 +00004172 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004173 if (field_type == Primitive::kPrimNot) {
4174 // Memory barriers, in the case of references, are also handled
4175 // in the previous switch statement.
4176 } else {
4177 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4178 }
Roland Levillain4d027112015-07-01 15:41:14 +01004179 }
Calin Juravle52c48962014-12-16 17:02:57 +00004180}
4181
4182void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4183 HandleFieldSet(instruction, instruction->GetFieldInfo());
4184}
4185
4186void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004187 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004188}
4189
4190void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4191 HandleFieldGet(instruction, instruction->GetFieldInfo());
4192}
4193
4194void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4195 HandleFieldGet(instruction, instruction->GetFieldInfo());
4196}
4197
4198void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4199 HandleFieldGet(instruction, instruction->GetFieldInfo());
4200}
4201
4202void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4203 HandleFieldGet(instruction, instruction->GetFieldInfo());
4204}
4205
4206void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4207 HandleFieldSet(instruction, instruction->GetFieldInfo());
4208}
4209
4210void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004211 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004212}
4213
Calin Juravlee460d1d2015-09-29 04:52:17 +01004214void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4215 HUnresolvedInstanceFieldGet* instruction) {
4216 FieldAccessCallingConventionARM calling_convention;
4217 codegen_->CreateUnresolvedFieldLocationSummary(
4218 instruction, instruction->GetFieldType(), calling_convention);
4219}
4220
4221void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4222 HUnresolvedInstanceFieldGet* instruction) {
4223 FieldAccessCallingConventionARM calling_convention;
4224 codegen_->GenerateUnresolvedFieldAccess(instruction,
4225 instruction->GetFieldType(),
4226 instruction->GetFieldIndex(),
4227 instruction->GetDexPc(),
4228 calling_convention);
4229}
4230
4231void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4232 HUnresolvedInstanceFieldSet* instruction) {
4233 FieldAccessCallingConventionARM calling_convention;
4234 codegen_->CreateUnresolvedFieldLocationSummary(
4235 instruction, instruction->GetFieldType(), calling_convention);
4236}
4237
4238void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4239 HUnresolvedInstanceFieldSet* instruction) {
4240 FieldAccessCallingConventionARM calling_convention;
4241 codegen_->GenerateUnresolvedFieldAccess(instruction,
4242 instruction->GetFieldType(),
4243 instruction->GetFieldIndex(),
4244 instruction->GetDexPc(),
4245 calling_convention);
4246}
4247
4248void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4249 HUnresolvedStaticFieldGet* instruction) {
4250 FieldAccessCallingConventionARM calling_convention;
4251 codegen_->CreateUnresolvedFieldLocationSummary(
4252 instruction, instruction->GetFieldType(), calling_convention);
4253}
4254
4255void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4256 HUnresolvedStaticFieldGet* instruction) {
4257 FieldAccessCallingConventionARM calling_convention;
4258 codegen_->GenerateUnresolvedFieldAccess(instruction,
4259 instruction->GetFieldType(),
4260 instruction->GetFieldIndex(),
4261 instruction->GetDexPc(),
4262 calling_convention);
4263}
4264
4265void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4266 HUnresolvedStaticFieldSet* instruction) {
4267 FieldAccessCallingConventionARM calling_convention;
4268 codegen_->CreateUnresolvedFieldLocationSummary(
4269 instruction, instruction->GetFieldType(), calling_convention);
4270}
4271
4272void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4273 HUnresolvedStaticFieldSet* instruction) {
4274 FieldAccessCallingConventionARM calling_convention;
4275 codegen_->GenerateUnresolvedFieldAccess(instruction,
4276 instruction->GetFieldType(),
4277 instruction->GetFieldIndex(),
4278 instruction->GetDexPc(),
4279 calling_convention);
4280}
4281
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004282void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004283 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4284 ? LocationSummary::kCallOnSlowPath
4285 : LocationSummary::kNoCall;
4286 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004287 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004288 if (instruction->HasUses()) {
4289 locations->SetOut(Location::SameAsFirstInput());
4290 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004291}
4292
Calin Juravle2ae48182016-03-16 14:05:09 +00004293void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4294 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004295 return;
4296 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004297 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004298
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004299 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004300 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004301}
4302
Calin Juravle2ae48182016-03-16 14:05:09 +00004303void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004304 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004305 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004306
4307 LocationSummary* locations = instruction->GetLocations();
4308 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004309
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004310 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004311}
4312
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004313void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004314 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004315}
4316
Artem Serov6c916792016-07-11 14:02:34 +01004317static LoadOperandType GetLoadOperandType(Primitive::Type type) {
4318 switch (type) {
4319 case Primitive::kPrimNot:
4320 return kLoadWord;
4321 case Primitive::kPrimBoolean:
4322 return kLoadUnsignedByte;
4323 case Primitive::kPrimByte:
4324 return kLoadSignedByte;
4325 case Primitive::kPrimChar:
4326 return kLoadUnsignedHalfword;
4327 case Primitive::kPrimShort:
4328 return kLoadSignedHalfword;
4329 case Primitive::kPrimInt:
4330 return kLoadWord;
4331 case Primitive::kPrimLong:
4332 return kLoadWordPair;
4333 case Primitive::kPrimFloat:
4334 return kLoadSWord;
4335 case Primitive::kPrimDouble:
4336 return kLoadDWord;
4337 default:
4338 LOG(FATAL) << "Unreachable type " << type;
4339 UNREACHABLE();
4340 }
4341}
4342
4343static StoreOperandType GetStoreOperandType(Primitive::Type type) {
4344 switch (type) {
4345 case Primitive::kPrimNot:
4346 return kStoreWord;
4347 case Primitive::kPrimBoolean:
4348 case Primitive::kPrimByte:
4349 return kStoreByte;
4350 case Primitive::kPrimChar:
4351 case Primitive::kPrimShort:
4352 return kStoreHalfword;
4353 case Primitive::kPrimInt:
4354 return kStoreWord;
4355 case Primitive::kPrimLong:
4356 return kStoreWordPair;
4357 case Primitive::kPrimFloat:
4358 return kStoreSWord;
4359 case Primitive::kPrimDouble:
4360 return kStoreDWord;
4361 default:
4362 LOG(FATAL) << "Unreachable type " << type;
4363 UNREACHABLE();
4364 }
4365}
4366
4367void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
4368 Location out_loc,
4369 Register base,
4370 Register reg_offset,
4371 Condition cond) {
4372 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4373 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4374
4375 switch (type) {
4376 case Primitive::kPrimByte:
4377 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
4378 break;
4379 case Primitive::kPrimBoolean:
4380 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
4381 break;
4382 case Primitive::kPrimShort:
4383 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
4384 break;
4385 case Primitive::kPrimChar:
4386 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
4387 break;
4388 case Primitive::kPrimNot:
4389 case Primitive::kPrimInt:
4390 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
4391 break;
4392 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
4393 case Primitive::kPrimLong:
4394 case Primitive::kPrimFloat:
4395 case Primitive::kPrimDouble:
4396 default:
4397 LOG(FATAL) << "Unreachable type " << type;
4398 UNREACHABLE();
4399 }
4400}
4401
4402void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
4403 Location loc,
4404 Register base,
4405 Register reg_offset,
4406 Condition cond) {
4407 uint32_t shift_count = Primitive::ComponentSizeShift(type);
4408 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
4409
4410 switch (type) {
4411 case Primitive::kPrimByte:
4412 case Primitive::kPrimBoolean:
4413 __ strb(loc.AsRegister<Register>(), mem_address, cond);
4414 break;
4415 case Primitive::kPrimShort:
4416 case Primitive::kPrimChar:
4417 __ strh(loc.AsRegister<Register>(), mem_address, cond);
4418 break;
4419 case Primitive::kPrimNot:
4420 case Primitive::kPrimInt:
4421 __ str(loc.AsRegister<Register>(), mem_address, cond);
4422 break;
4423 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
4424 case Primitive::kPrimLong:
4425 case Primitive::kPrimFloat:
4426 case Primitive::kPrimDouble:
4427 default:
4428 LOG(FATAL) << "Unreachable type " << type;
4429 UNREACHABLE();
4430 }
4431}
4432
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004433void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004434 bool object_array_get_with_read_barrier =
4435 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004436 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004437 new (GetGraph()->GetArena()) LocationSummary(instruction,
4438 object_array_get_with_read_barrier ?
4439 LocationSummary::kCallOnSlowPath :
4440 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004441 locations->SetInAt(0, Location::RequiresRegister());
4442 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004443 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4444 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4445 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004446 // The output overlaps in the case of an object array get with
4447 // read barriers enabled: we do not want the move to overwrite the
4448 // array's location, as we need it to emit the read barrier.
4449 locations->SetOut(
4450 Location::RequiresRegister(),
4451 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004452 }
Roland Levillainc9285912015-12-18 10:38:42 +00004453 // We need a temporary register for the read barrier marking slow
4454 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4455 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4456 locations->AddTemp(Location::RequiresRegister());
4457 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004458}
4459
4460void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4461 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004462 Location obj_loc = locations->InAt(0);
4463 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004464 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004465 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01004466 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00004467 Primitive::Type type = instruction->GetType();
Artem Serov328429f2016-07-06 16:23:04 +01004468 HInstruction* array_instr = instruction->GetArray();
4469 bool has_intermediate_address = array_instr->IsIntermediateAddress();
4470 // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4471 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
Artem Serov6c916792016-07-11 14:02:34 +01004472
Roland Levillain4d027112015-07-01 15:41:14 +01004473 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01004474 case Primitive::kPrimBoolean:
4475 case Primitive::kPrimByte:
4476 case Primitive::kPrimShort:
4477 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00004478 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004479 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01004480 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
4481 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
4482
4483 LoadOperandType load_type = GetLoadOperandType(type);
4484 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004485 } else {
Artem Serov328429f2016-07-06 16:23:04 +01004486 Register temp = IP;
4487
4488 if (has_intermediate_address) {
4489 // We do not need to compute the intermediate address from the array: the
4490 // input instruction has done it already. See the comment in
4491 // `TryExtractArrayAccessAddress()`.
4492 if (kIsDebugBuild) {
4493 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4494 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4495 }
4496 temp = obj;
4497 } else {
4498 __ add(temp, obj, ShifterOperand(data_offset));
4499 }
4500 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004501 }
4502 break;
4503 }
4504
Roland Levillainc9285912015-12-18 10:38:42 +00004505 case Primitive::kPrimNot: {
4506 static_assert(
4507 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4508 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00004509 // /* HeapReference<Object> */ out =
4510 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4511 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4512 Location temp = locations->GetTemp(0);
4513 // Note that a potential implicit null check is handled in this
4514 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4515 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4516 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4517 } else {
4518 Register out = out_loc.AsRegister<Register>();
4519 if (index.IsConstant()) {
4520 size_t offset =
4521 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4522 __ LoadFromOffset(kLoadWord, out, obj, offset);
4523 codegen_->MaybeRecordImplicitNullCheck(instruction);
4524 // If read barriers are enabled, emit read barriers other than
4525 // Baker's using a slow path (and also unpoison the loaded
4526 // reference, if heap poisoning is enabled).
4527 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4528 } else {
Artem Serov328429f2016-07-06 16:23:04 +01004529 Register temp = IP;
4530
4531 if (has_intermediate_address) {
4532 // We do not need to compute the intermediate address from the array: the
4533 // input instruction has done it already. See the comment in
4534 // `TryExtractArrayAccessAddress()`.
4535 if (kIsDebugBuild) {
4536 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4537 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
4538 }
4539 temp = obj;
4540 } else {
4541 __ add(temp, obj, ShifterOperand(data_offset));
4542 }
4543 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01004544
Roland Levillainc9285912015-12-18 10:38:42 +00004545 codegen_->MaybeRecordImplicitNullCheck(instruction);
4546 // If read barriers are enabled, emit read barriers other than
4547 // Baker's using a slow path (and also unpoison the loaded
4548 // reference, if heap poisoning is enabled).
4549 codegen_->MaybeGenerateReadBarrierSlow(
4550 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4551 }
4552 }
4553 break;
4554 }
4555
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004556 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004557 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004558 size_t offset =
4559 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004560 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004561 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004562 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004563 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004564 }
4565 break;
4566 }
4567
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004568 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00004569 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004570 if (index.IsConstant()) {
4571 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004572 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004573 } else {
4574 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00004575 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004576 }
4577 break;
4578 }
4579
4580 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00004581 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004582 if (index.IsConstant()) {
4583 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004584 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004585 } else {
4586 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004587 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004588 }
4589 break;
4590 }
4591
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004592 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004593 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004594 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004595 }
Roland Levillain4d027112015-07-01 15:41:14 +01004596
4597 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00004598 // Potential implicit null checks, in the case of reference
4599 // arrays, are handled in the previous switch statement.
4600 } else {
4601 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004602 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004603}
4604
4605void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004606 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004607
4608 bool needs_write_barrier =
4609 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004610 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4611 bool object_array_set_with_read_barrier =
4612 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004613
Nicolas Geoffray39468442014-09-02 15:17:15 +01004614 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004615 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004616 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4617 LocationSummary::kCallOnSlowPath :
4618 LocationSummary::kNoCall);
4619
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004620 locations->SetInAt(0, Location::RequiresRegister());
4621 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4622 if (Primitive::IsFloatingPointType(value_type)) {
4623 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004624 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004625 locations->SetInAt(2, Location::RequiresRegister());
4626 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004627 if (needs_write_barrier) {
4628 // Temporary registers for the write barrier.
4629 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004630 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004631 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004632}
4633
4634void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4635 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004636 Location array_loc = locations->InAt(0);
4637 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004638 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004639 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004640 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004641 bool needs_write_barrier =
4642 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01004643 uint32_t data_offset =
4644 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
4645 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01004646 HInstruction* array_instr = instruction->GetArray();
4647 bool has_intermediate_address = array_instr->IsIntermediateAddress();
4648 // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4649 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004650
4651 switch (value_type) {
4652 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01004653 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004654 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01004655 case Primitive::kPrimChar:
4656 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004657 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01004658 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
4659 uint32_t full_offset =
4660 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
4661 StoreOperandType store_type = GetStoreOperandType(value_type);
4662 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004663 } else {
Artem Serov328429f2016-07-06 16:23:04 +01004664 Register temp = IP;
4665
4666 if (has_intermediate_address) {
4667 // We do not need to compute the intermediate address from the array: the
4668 // input instruction has done it already. See the comment in
4669 // `TryExtractArrayAccessAddress()`.
4670 if (kIsDebugBuild) {
4671 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
4672 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
4673 }
4674 temp = array;
4675 } else {
4676 __ add(temp, array, ShifterOperand(data_offset));
4677 }
Artem Serov6c916792016-07-11 14:02:34 +01004678 codegen_->StoreToShiftedRegOffset(value_type,
4679 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01004680 temp,
Artem Serov6c916792016-07-11 14:02:34 +01004681 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004682 }
4683 break;
4684 }
4685
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004686 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00004687 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01004688 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
4689 // See the comment in instruction_simplifier_shared.cc.
4690 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004691
4692 if (instruction->InputAt(2)->IsNullConstant()) {
4693 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004694 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004695 size_t offset =
4696 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01004697 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004698 } else {
4699 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01004700 __ add(IP, array, ShifterOperand(data_offset));
4701 codegen_->StoreToShiftedRegOffset(value_type,
4702 value_loc,
4703 IP,
4704 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004705 }
Roland Levillain1407ee72016-01-08 15:56:19 +00004706 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00004707 DCHECK(!needs_write_barrier);
4708 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004709 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004710 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004711
4712 DCHECK(needs_write_barrier);
4713 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4714 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4715 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4716 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4717 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4718 Label done;
4719 SlowPathCode* slow_path = nullptr;
4720
Roland Levillain3b359c72015-11-17 19:35:12 +00004721 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004722 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4723 codegen_->AddSlowPath(slow_path);
4724 if (instruction->GetValueCanBeNull()) {
4725 Label non_zero;
4726 __ CompareAndBranchIfNonZero(value, &non_zero);
4727 if (index.IsConstant()) {
4728 size_t offset =
4729 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4730 __ StoreToOffset(kStoreWord, value, array, offset);
4731 } else {
4732 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01004733 __ add(IP, array, ShifterOperand(data_offset));
4734 codegen_->StoreToShiftedRegOffset(value_type,
4735 value_loc,
4736 IP,
4737 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004738 }
4739 codegen_->MaybeRecordImplicitNullCheck(instruction);
4740 __ b(&done);
4741 __ Bind(&non_zero);
4742 }
4743
Roland Levillain3b359c72015-11-17 19:35:12 +00004744 if (kEmitCompilerReadBarrier) {
4745 // When read barriers are enabled, the type checking
4746 // instrumentation requires two read barriers:
4747 //
4748 // __ Mov(temp2, temp1);
4749 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4750 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004751 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004752 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4753 //
4754 // // /* HeapReference<Class> */ temp2 = value->klass_
4755 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004756 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004757 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4758 //
4759 // __ cmp(temp1, ShifterOperand(temp2));
4760 //
4761 // However, the second read barrier may trash `temp`, as it
4762 // is a temporary register, and as such would not be saved
4763 // along with live registers before calling the runtime (nor
4764 // restored afterwards). So in this case, we bail out and
4765 // delegate the work to the array set slow path.
4766 //
4767 // TODO: Extend the register allocator to support a new
4768 // "(locally) live temp" location so as to avoid always
4769 // going into the slow path when read barriers are enabled.
4770 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004771 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004772 // /* HeapReference<Class> */ temp1 = array->klass_
4773 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4774 codegen_->MaybeRecordImplicitNullCheck(instruction);
4775 __ MaybeUnpoisonHeapReference(temp1);
4776
4777 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4778 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4779 // /* HeapReference<Class> */ temp2 = value->klass_
4780 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4781 // If heap poisoning is enabled, no need to unpoison `temp1`
4782 // nor `temp2`, as we are comparing two poisoned references.
4783 __ cmp(temp1, ShifterOperand(temp2));
4784
4785 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4786 Label do_put;
4787 __ b(&do_put, EQ);
4788 // If heap poisoning is enabled, the `temp1` reference has
4789 // not been unpoisoned yet; unpoison it now.
4790 __ MaybeUnpoisonHeapReference(temp1);
4791
4792 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4793 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4794 // If heap poisoning is enabled, no need to unpoison
4795 // `temp1`, as we are comparing against null below.
4796 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4797 __ Bind(&do_put);
4798 } else {
4799 __ b(slow_path->GetEntryLabel(), NE);
4800 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004801 }
4802 }
4803
Artem Serov6c916792016-07-11 14:02:34 +01004804 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004805 if (kPoisonHeapReferences) {
4806 // Note that in the case where `value` is a null reference,
4807 // we do not enter this block, as a null reference does not
4808 // need poisoning.
4809 DCHECK_EQ(value_type, Primitive::kPrimNot);
4810 __ Mov(temp1, value);
4811 __ PoisonHeapReference(temp1);
4812 source = temp1;
4813 }
4814
4815 if (index.IsConstant()) {
4816 size_t offset =
4817 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4818 __ StoreToOffset(kStoreWord, source, array, offset);
4819 } else {
4820 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01004821
4822 __ add(IP, array, ShifterOperand(data_offset));
4823 codegen_->StoreToShiftedRegOffset(value_type,
4824 Location::RegisterLocation(source),
4825 IP,
4826 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004827 }
4828
Roland Levillain3b359c72015-11-17 19:35:12 +00004829 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004830 codegen_->MaybeRecordImplicitNullCheck(instruction);
4831 }
4832
4833 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4834
4835 if (done.IsLinked()) {
4836 __ Bind(&done);
4837 }
4838
4839 if (slow_path != nullptr) {
4840 __ Bind(slow_path->GetExitLabel());
4841 }
4842
4843 break;
4844 }
4845
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004846 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004847 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004848 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004849 size_t offset =
4850 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004851 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004852 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004853 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004854 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004855 }
4856 break;
4857 }
4858
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004859 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004860 Location value = locations->InAt(2);
4861 DCHECK(value.IsFpuRegister());
4862 if (index.IsConstant()) {
4863 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004864 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004865 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004866 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004867 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4868 }
4869 break;
4870 }
4871
4872 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004873 Location value = locations->InAt(2);
4874 DCHECK(value.IsFpuRegisterPair());
4875 if (index.IsConstant()) {
4876 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004877 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004878 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004879 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004880 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4881 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004882
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004883 break;
4884 }
4885
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004886 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004887 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004888 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004889 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004890
Roland Levillain80e67092016-01-08 16:04:55 +00004891 // Objects are handled in the switch.
4892 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004893 codegen_->MaybeRecordImplicitNullCheck(instruction);
4894 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004895}
4896
4897void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004898 LocationSummary* locations =
4899 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004900 locations->SetInAt(0, Location::RequiresRegister());
4901 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004902}
4903
4904void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4905 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01004906 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004907 Register obj = locations->InAt(0).AsRegister<Register>();
4908 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004909 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004910 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004911}
4912
Artem Serov328429f2016-07-06 16:23:04 +01004913void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
4914 // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4915 DCHECK(!kEmitCompilerReadBarrier);
4916 LocationSummary* locations =
4917 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4918
4919 locations->SetInAt(0, Location::RequiresRegister());
4920 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
4921 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4922}
4923
4924void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
4925 LocationSummary* locations = instruction->GetLocations();
4926 Location out = locations->Out();
4927 Location first = locations->InAt(0);
4928 Location second = locations->InAt(1);
4929
4930 // The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
4931 DCHECK(!kEmitCompilerReadBarrier);
4932
4933 if (second.IsRegister()) {
4934 __ add(out.AsRegister<Register>(),
4935 first.AsRegister<Register>(),
4936 ShifterOperand(second.AsRegister<Register>()));
4937 } else {
4938 __ AddConstant(out.AsRegister<Register>(),
4939 first.AsRegister<Register>(),
4940 second.GetConstant()->AsIntConstant()->GetValue());
4941 }
4942}
4943
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004944void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004945 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4946 ? LocationSummary::kCallOnSlowPath
4947 : LocationSummary::kNoCall;
4948 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004949 locations->SetInAt(0, Location::RequiresRegister());
4950 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004951 if (instruction->HasUses()) {
4952 locations->SetOut(Location::SameAsFirstInput());
4953 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004954}
4955
4956void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4957 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004958 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004959 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004960 codegen_->AddSlowPath(slow_path);
4961
Roland Levillain271ab9c2014-11-27 15:23:57 +00004962 Register index = locations->InAt(0).AsRegister<Register>();
4963 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004964
4965 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004966 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004967}
4968
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004969void CodeGeneratorARM::MarkGCCard(Register temp,
4970 Register card,
4971 Register object,
4972 Register value,
4973 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004974 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004975 if (can_be_null) {
4976 __ CompareAndBranchIfZero(value, &is_null);
4977 }
Andreas Gampe542451c2016-07-26 09:02:02 -07004978 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004979 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4980 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004981 if (can_be_null) {
4982 __ Bind(&is_null);
4983 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004984}
4985
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004986void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004987 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004988}
4989
4990void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004991 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4992}
4993
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004994void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4995 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4996}
4997
4998void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004999 HBasicBlock* block = instruction->GetBlock();
5000 if (block->GetLoopInformation() != nullptr) {
5001 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5002 // The back edge will generate the suspend check.
5003 return;
5004 }
5005 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5006 // The goto will generate the suspend check.
5007 return;
5008 }
5009 GenerateSuspendCheck(instruction, nullptr);
5010}
5011
5012void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
5013 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005014 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01005015 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
5016 if (slow_path == nullptr) {
5017 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
5018 instruction->SetSlowPath(slow_path);
5019 codegen_->AddSlowPath(slow_path);
5020 if (successor != nullptr) {
5021 DCHECK(successor->IsLoopHeader());
5022 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
5023 }
5024 } else {
5025 DCHECK_EQ(slow_path->GetSuccessor(), successor);
5026 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005027
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00005028 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07005029 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005030 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005031 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005032 __ Bind(slow_path->GetReturnLabel());
5033 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005034 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01005035 __ b(slow_path->GetEntryLabel());
5036 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00005037}
5038
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005039ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
5040 return codegen_->GetAssembler();
5041}
5042
5043void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005044 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005045 Location source = move->GetSource();
5046 Location destination = move->GetDestination();
5047
5048 if (source.IsRegister()) {
5049 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005050 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005051 } else if (destination.IsFpuRegister()) {
5052 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005053 } else {
5054 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005055 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005056 SP, destination.GetStackIndex());
5057 }
5058 } else if (source.IsStackSlot()) {
5059 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005060 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005061 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005062 } else if (destination.IsFpuRegister()) {
5063 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005064 } else {
5065 DCHECK(destination.IsStackSlot());
5066 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
5067 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5068 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005069 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005070 if (destination.IsRegister()) {
5071 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
5072 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005073 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005074 } else {
5075 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005076 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
5077 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005078 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005079 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005080 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
5081 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005082 } else if (destination.IsRegisterPair()) {
5083 DCHECK(ExpectedPairLayout(destination));
5084 __ LoadFromOffset(
5085 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
5086 } else {
5087 DCHECK(destination.IsFpuRegisterPair()) << destination;
5088 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5089 SP,
5090 source.GetStackIndex());
5091 }
5092 } else if (source.IsRegisterPair()) {
5093 if (destination.IsRegisterPair()) {
5094 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
5095 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00005096 } else if (destination.IsFpuRegisterPair()) {
5097 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5098 source.AsRegisterPairLow<Register>(),
5099 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005100 } else {
5101 DCHECK(destination.IsDoubleStackSlot()) << destination;
5102 DCHECK(ExpectedPairLayout(source));
5103 __ StoreToOffset(
5104 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
5105 }
5106 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00005107 if (destination.IsRegisterPair()) {
5108 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5109 destination.AsRegisterPairHigh<Register>(),
5110 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5111 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005112 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
5113 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
5114 } else {
5115 DCHECK(destination.IsDoubleStackSlot()) << destination;
5116 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
5117 SP,
5118 destination.GetStackIndex());
5119 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005120 } else {
5121 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00005122 HConstant* constant = source.GetConstant();
5123 if (constant->IsIntConstant() || constant->IsNullConstant()) {
5124 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005125 if (destination.IsRegister()) {
5126 __ LoadImmediate(destination.AsRegister<Register>(), value);
5127 } else {
5128 DCHECK(destination.IsStackSlot());
5129 __ LoadImmediate(IP, value);
5130 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5131 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005132 } else if (constant->IsLongConstant()) {
5133 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005134 if (destination.IsRegisterPair()) {
5135 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5136 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005137 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005138 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005139 __ LoadImmediate(IP, Low32Bits(value));
5140 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5141 __ LoadImmediate(IP, High32Bits(value));
5142 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5143 }
5144 } else if (constant->IsDoubleConstant()) {
5145 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005146 if (destination.IsFpuRegisterPair()) {
5147 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005148 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005149 DCHECK(destination.IsDoubleStackSlot()) << destination;
5150 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005151 __ LoadImmediate(IP, Low32Bits(int_value));
5152 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5153 __ LoadImmediate(IP, High32Bits(int_value));
5154 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5155 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005156 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005157 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005158 float value = constant->AsFloatConstant()->GetValue();
5159 if (destination.IsFpuRegister()) {
5160 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5161 } else {
5162 DCHECK(destination.IsStackSlot());
5163 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5164 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5165 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005166 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005167 }
5168}
5169
5170void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5171 __ Mov(IP, reg);
5172 __ LoadFromOffset(kLoadWord, reg, SP, mem);
5173 __ StoreToOffset(kStoreWord, IP, SP, mem);
5174}
5175
5176void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5177 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5178 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5179 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5180 SP, mem1 + stack_offset);
5181 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5182 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5183 SP, mem2 + stack_offset);
5184 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5185}
5186
5187void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005188 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005189 Location source = move->GetSource();
5190 Location destination = move->GetDestination();
5191
5192 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005193 DCHECK_NE(source.AsRegister<Register>(), IP);
5194 DCHECK_NE(destination.AsRegister<Register>(), IP);
5195 __ Mov(IP, source.AsRegister<Register>());
5196 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5197 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005198 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005199 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005200 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005201 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005202 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5203 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005204 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005205 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005206 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005207 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005208 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005209 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005210 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005211 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005212 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5213 destination.AsRegisterPairHigh<Register>(),
5214 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005215 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005216 Register low_reg = source.IsRegisterPair()
5217 ? source.AsRegisterPairLow<Register>()
5218 : destination.AsRegisterPairLow<Register>();
5219 int mem = source.IsRegisterPair()
5220 ? destination.GetStackIndex()
5221 : source.GetStackIndex();
5222 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005223 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005224 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005225 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005226 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005227 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5228 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005229 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005230 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005231 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005232 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5233 DRegister reg = source.IsFpuRegisterPair()
5234 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5235 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5236 int mem = source.IsFpuRegisterPair()
5237 ? destination.GetStackIndex()
5238 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005239 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005240 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005241 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005242 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5243 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5244 : destination.AsFpuRegister<SRegister>();
5245 int mem = source.IsFpuRegister()
5246 ? destination.GetStackIndex()
5247 : source.GetStackIndex();
5248
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005249 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005250 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005251 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005252 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005253 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5254 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005255 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005256 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005257 }
5258}
5259
5260void ParallelMoveResolverARM::SpillScratch(int reg) {
5261 __ Push(static_cast<Register>(reg));
5262}
5263
5264void ParallelMoveResolverARM::RestoreScratch(int reg) {
5265 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005266}
5267
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005268HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5269 HLoadClass::LoadKind desired_class_load_kind) {
5270 if (kEmitCompilerReadBarrier) {
5271 switch (desired_class_load_kind) {
5272 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5273 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5274 case HLoadClass::LoadKind::kBootImageAddress:
5275 // TODO: Implement for read barrier.
5276 return HLoadClass::LoadKind::kDexCacheViaMethod;
5277 default:
5278 break;
5279 }
5280 }
5281 switch (desired_class_load_kind) {
5282 case HLoadClass::LoadKind::kReferrersClass:
5283 break;
5284 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5285 DCHECK(!GetCompilerOptions().GetCompilePic());
5286 break;
5287 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5288 DCHECK(GetCompilerOptions().GetCompilePic());
5289 break;
5290 case HLoadClass::LoadKind::kBootImageAddress:
5291 break;
5292 case HLoadClass::LoadKind::kDexCacheAddress:
5293 DCHECK(Runtime::Current()->UseJitCompilation());
5294 break;
5295 case HLoadClass::LoadKind::kDexCachePcRelative:
5296 DCHECK(!Runtime::Current()->UseJitCompilation());
5297 // We disable pc-relative load when there is an irreducible loop, as the optimization
5298 // is incompatible with it.
5299 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5300 // with irreducible loops.
5301 if (GetGraph()->HasIrreducibleLoops()) {
5302 return HLoadClass::LoadKind::kDexCacheViaMethod;
5303 }
5304 break;
5305 case HLoadClass::LoadKind::kDexCacheViaMethod:
5306 break;
5307 }
5308 return desired_class_load_kind;
5309}
5310
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005311void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005312 if (cls->NeedsAccessCheck()) {
5313 InvokeRuntimeCallingConvention calling_convention;
5314 CodeGenerator::CreateLoadClassLocationSummary(
5315 cls,
5316 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5317 Location::RegisterLocation(R0),
5318 /* code_generator_supports_read_barrier */ true);
5319 return;
5320 }
5321
5322 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
5323 ? LocationSummary::kCallOnSlowPath
5324 : LocationSummary::kNoCall;
5325 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
5326 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5327 if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
5328 load_kind == HLoadClass::LoadKind::kDexCacheViaMethod ||
5329 load_kind == HLoadClass::LoadKind::kDexCachePcRelative) {
5330 locations->SetInAt(0, Location::RequiresRegister());
5331 }
5332 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005333}
5334
5335void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005336 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005337 if (cls->NeedsAccessCheck()) {
5338 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5339 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5340 cls,
5341 cls->GetDexPc(),
5342 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005343 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005344 return;
5345 }
5346
Roland Levillain3b359c72015-11-17 19:35:12 +00005347 Location out_loc = locations->Out();
5348 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005349
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005350 bool generate_null_check = false;
5351 switch (cls->GetLoadKind()) {
5352 case HLoadClass::LoadKind::kReferrersClass: {
5353 DCHECK(!cls->CanCallRuntime());
5354 DCHECK(!cls->MustGenerateClinitCheck());
5355 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5356 Register current_method = locations->InAt(0).AsRegister<Register>();
5357 GenerateGcRootFieldLoad(
5358 cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5359 break;
5360 }
5361 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
5362 DCHECK(!kEmitCompilerReadBarrier);
5363 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5364 cls->GetTypeIndex()));
5365 break;
5366 }
5367 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5368 DCHECK(!kEmitCompilerReadBarrier);
5369 CodeGeneratorARM::PcRelativePatchInfo* labels =
5370 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5371 __ BindTrackedLabel(&labels->movw_label);
5372 __ movw(out, /* placeholder */ 0u);
5373 __ BindTrackedLabel(&labels->movt_label);
5374 __ movt(out, /* placeholder */ 0u);
5375 __ BindTrackedLabel(&labels->add_pc_label);
5376 __ add(out, out, ShifterOperand(PC));
5377 break;
5378 }
5379 case HLoadClass::LoadKind::kBootImageAddress: {
5380 DCHECK(!kEmitCompilerReadBarrier);
5381 DCHECK_NE(cls->GetAddress(), 0u);
5382 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5383 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5384 break;
5385 }
5386 case HLoadClass::LoadKind::kDexCacheAddress: {
5387 DCHECK_NE(cls->GetAddress(), 0u);
5388 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5389 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5390 // a 128B range. To try and reduce the number of literals if we load multiple types,
5391 // simply split the dex cache address to a 128B aligned base loaded from a literal
5392 // and the remaining offset embedded in the load.
5393 static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
5394 DCHECK_ALIGNED(cls->GetAddress(), 4u);
5395 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5396 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5397 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5398 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5399 // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
5400 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5401 generate_null_check = !cls->IsInDexCache();
5402 break;
5403 }
5404 case HLoadClass::LoadKind::kDexCachePcRelative: {
5405 Register base_reg = locations->InAt(0).AsRegister<Register>();
5406 HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase();
5407 int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset();
5408 // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
5409 GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset);
5410 generate_null_check = !cls->IsInDexCache();
5411 break;
5412 }
5413 case HLoadClass::LoadKind::kDexCacheViaMethod: {
5414 // /* GcRoot<mirror::Class>[] */ out =
5415 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
5416 Register current_method = locations->InAt(0).AsRegister<Register>();
5417 __ LoadFromOffset(kLoadWord,
5418 out,
5419 current_method,
5420 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5421 // /* GcRoot<mirror::Class> */ out = out[type_index]
5422 size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5423 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5424 generate_null_check = !cls->IsInDexCache();
5425 }
5426 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005427
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005428 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5429 DCHECK(cls->CanCallRuntime());
5430 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5431 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5432 codegen_->AddSlowPath(slow_path);
5433 if (generate_null_check) {
5434 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5435 }
5436 if (cls->MustGenerateClinitCheck()) {
5437 GenerateClassInitializationCheck(slow_path, out);
5438 } else {
5439 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005440 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005441 }
5442}
5443
5444void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5445 LocationSummary* locations =
5446 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5447 locations->SetInAt(0, Location::RequiresRegister());
5448 if (check->HasUses()) {
5449 locations->SetOut(Location::SameAsFirstInput());
5450 }
5451}
5452
5453void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005454 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005455 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005456 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005457 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005458 GenerateClassInitializationCheck(slow_path,
5459 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005460}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005461
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005462void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005463 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005464 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5465 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5466 __ b(slow_path->GetEntryLabel(), LT);
5467 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5468 // properly. Therefore, we do a memory fence.
5469 __ dmb(ISH);
5470 __ Bind(slow_path->GetExitLabel());
5471}
5472
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005473HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5474 HLoadString::LoadKind desired_string_load_kind) {
5475 if (kEmitCompilerReadBarrier) {
5476 switch (desired_string_load_kind) {
5477 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5478 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5479 case HLoadString::LoadKind::kBootImageAddress:
5480 // TODO: Implement for read barrier.
5481 return HLoadString::LoadKind::kDexCacheViaMethod;
5482 default:
5483 break;
5484 }
5485 }
5486 switch (desired_string_load_kind) {
5487 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5488 DCHECK(!GetCompilerOptions().GetCompilePic());
5489 break;
5490 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5491 DCHECK(GetCompilerOptions().GetCompilePic());
5492 break;
5493 case HLoadString::LoadKind::kBootImageAddress:
5494 break;
5495 case HLoadString::LoadKind::kDexCacheAddress:
Calin Juravleffc87072016-04-20 14:22:09 +01005496 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005497 break;
5498 case HLoadString::LoadKind::kDexCachePcRelative:
Calin Juravleffc87072016-04-20 14:22:09 +01005499 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005500 // We disable pc-relative load when there is an irreducible loop, as the optimization
5501 // is incompatible with it.
5502 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5503 // with irreducible loops.
5504 if (GetGraph()->HasIrreducibleLoops()) {
5505 return HLoadString::LoadKind::kDexCacheViaMethod;
5506 }
5507 break;
5508 case HLoadString::LoadKind::kDexCacheViaMethod:
5509 break;
5510 }
5511 return desired_string_load_kind;
5512}
5513
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005514void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005515 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005516 ? LocationSummary::kCallOnSlowPath
5517 : LocationSummary::kNoCall;
5518 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005519 HLoadString::LoadKind load_kind = load->GetLoadKind();
5520 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5521 load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5522 locations->SetInAt(0, Location::RequiresRegister());
5523 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005524 locations->SetOut(Location::RequiresRegister());
5525}
5526
5527void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005528 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005529 Location out_loc = locations->Out();
5530 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005531
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005532 switch (load->GetLoadKind()) {
5533 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5534 DCHECK(!kEmitCompilerReadBarrier);
5535 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5536 load->GetStringIndex()));
5537 return; // No dex cache slow path.
5538 }
5539 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5540 DCHECK(!kEmitCompilerReadBarrier);
5541 CodeGeneratorARM::PcRelativePatchInfo* labels =
5542 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5543 __ BindTrackedLabel(&labels->movw_label);
5544 __ movw(out, /* placeholder */ 0u);
5545 __ BindTrackedLabel(&labels->movt_label);
5546 __ movt(out, /* placeholder */ 0u);
5547 __ BindTrackedLabel(&labels->add_pc_label);
5548 __ add(out, out, ShifterOperand(PC));
5549 return; // No dex cache slow path.
5550 }
5551 case HLoadString::LoadKind::kBootImageAddress: {
5552 DCHECK(!kEmitCompilerReadBarrier);
5553 DCHECK_NE(load->GetAddress(), 0u);
5554 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5555 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5556 return; // No dex cache slow path.
5557 }
5558 case HLoadString::LoadKind::kDexCacheAddress: {
5559 DCHECK_NE(load->GetAddress(), 0u);
5560 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5561 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5562 // a 128B range. To try and reduce the number of literals if we load multiple strings,
5563 // simply split the dex cache address to a 128B aligned base loaded from a literal
5564 // and the remaining offset embedded in the load.
5565 static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5566 DCHECK_ALIGNED(load->GetAddress(), 4u);
5567 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5568 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5569 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5570 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005571 // /* GcRoot<mirror::String> */ out = *(base_address + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005572 GenerateGcRootFieldLoad(load, out_loc, out, offset);
5573 break;
5574 }
5575 case HLoadString::LoadKind::kDexCachePcRelative: {
5576 Register base_reg = locations->InAt(0).AsRegister<Register>();
5577 HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5578 int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005579 // /* GcRoot<mirror::String> */ out = *(dex_cache_arrays_base + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005580 GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5581 break;
5582 }
5583 case HLoadString::LoadKind::kDexCacheViaMethod: {
5584 Register current_method = locations->InAt(0).AsRegister<Register>();
5585
5586 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5587 GenerateGcRootFieldLoad(
5588 load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5589 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5590 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5591 // /* GcRoot<mirror::String> */ out = out[string_index]
5592 GenerateGcRootFieldLoad(
5593 load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5594 break;
5595 }
5596 default:
5597 LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5598 UNREACHABLE();
5599 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005600
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005601 if (!load->IsInDexCache()) {
5602 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5603 codegen_->AddSlowPath(slow_path);
5604 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5605 __ Bind(slow_path->GetExitLabel());
5606 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005607}
5608
David Brazdilcb1c0552015-08-04 16:22:25 +01005609static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07005610 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01005611}
5612
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005613void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5614 LocationSummary* locations =
5615 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5616 locations->SetOut(Location::RequiresRegister());
5617}
5618
5619void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005620 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005621 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5622}
5623
5624void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5625 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5626}
5627
5628void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005629 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005630 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005631}
5632
5633void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5634 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005635 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005636 InvokeRuntimeCallingConvention calling_convention;
5637 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5638}
5639
5640void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5641 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005642 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005643 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005644}
5645
Roland Levillainc9285912015-12-18 10:38:42 +00005646static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5647 return kEmitCompilerReadBarrier &&
5648 (kUseBakerReadBarrier ||
5649 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5650 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5651 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5652}
5653
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005654void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005655 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005656 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5657 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005658 case TypeCheckKind::kExactCheck:
5659 case TypeCheckKind::kAbstractClassCheck:
5660 case TypeCheckKind::kClassHierarchyCheck:
5661 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005662 call_kind =
5663 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005664 break;
5665 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005666 case TypeCheckKind::kUnresolvedCheck:
5667 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005668 call_kind = LocationSummary::kCallOnSlowPath;
5669 break;
5670 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005671
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005672 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005673 locations->SetInAt(0, Location::RequiresRegister());
5674 locations->SetInAt(1, Location::RequiresRegister());
5675 // The "out" register is used as a temporary, so it overlaps with the inputs.
5676 // Note that TypeCheckSlowPathARM uses this register too.
5677 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5678 // When read barriers are enabled, we need a temporary register for
5679 // some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005680 if (TypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005681 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005682 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005683}
5684
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005685void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005686 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005687 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005688 Location obj_loc = locations->InAt(0);
5689 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005690 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005691 Location out_loc = locations->Out();
5692 Register out = out_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005693 Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005694 locations->GetTemp(0) :
5695 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005696 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005697 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5698 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5699 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005700 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005701 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005702
5703 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005704 // avoid null check if we know obj is not null.
5705 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005706 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005707 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005708
Roland Levillain3b359c72015-11-17 19:35:12 +00005709 // /* HeapReference<Class> */ out = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005710 GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005711
Roland Levillainc9285912015-12-18 10:38:42 +00005712 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005713 case TypeCheckKind::kExactCheck: {
5714 __ cmp(out, ShifterOperand(cls));
5715 // Classes must be equal for the instanceof to succeed.
5716 __ b(&zero, NE);
5717 __ LoadImmediate(out, 1);
5718 __ b(&done);
5719 break;
5720 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005721
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005722 case TypeCheckKind::kAbstractClassCheck: {
5723 // If the class is abstract, we eagerly fetch the super class of the
5724 // object to avoid doing a comparison we know will fail.
5725 Label loop;
5726 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005727 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005728 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005729 // If `out` is null, we use it for the result, and jump to `done`.
5730 __ CompareAndBranchIfZero(out, &done);
5731 __ cmp(out, ShifterOperand(cls));
5732 __ b(&loop, NE);
5733 __ LoadImmediate(out, 1);
5734 if (zero.IsLinked()) {
5735 __ b(&done);
5736 }
5737 break;
5738 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005739
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005740 case TypeCheckKind::kClassHierarchyCheck: {
5741 // Walk over the class hierarchy to find a match.
5742 Label loop, success;
5743 __ Bind(&loop);
5744 __ cmp(out, ShifterOperand(cls));
5745 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005746 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005747 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005748 __ CompareAndBranchIfNonZero(out, &loop);
5749 // If `out` is null, we use it for the result, and jump to `done`.
5750 __ b(&done);
5751 __ Bind(&success);
5752 __ LoadImmediate(out, 1);
5753 if (zero.IsLinked()) {
5754 __ b(&done);
5755 }
5756 break;
5757 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005758
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005759 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005760 // Do an exact check.
5761 Label exact_check;
5762 __ cmp(out, ShifterOperand(cls));
5763 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005764 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005765 // /* HeapReference<Class> */ out = out->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005766 GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005767 // If `out` is null, we use it for the result, and jump to `done`.
5768 __ CompareAndBranchIfZero(out, &done);
5769 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5770 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5771 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005772 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005773 __ LoadImmediate(out, 1);
5774 __ b(&done);
5775 break;
5776 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005777
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005778 case TypeCheckKind::kArrayCheck: {
5779 __ cmp(out, ShifterOperand(cls));
5780 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005781 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5782 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005783 codegen_->AddSlowPath(slow_path);
5784 __ b(slow_path->GetEntryLabel(), NE);
5785 __ LoadImmediate(out, 1);
5786 if (zero.IsLinked()) {
5787 __ b(&done);
5788 }
5789 break;
5790 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005791
Calin Juravle98893e12015-10-02 21:05:03 +01005792 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005793 case TypeCheckKind::kInterfaceCheck: {
5794 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005795 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00005796 // cases.
5797 //
5798 // We cannot directly call the InstanceofNonTrivial runtime
5799 // entry point without resorting to a type checking slow path
5800 // here (i.e. by calling InvokeRuntime directly), as it would
5801 // require to assign fixed registers for the inputs of this
5802 // HInstanceOf instruction (following the runtime calling
5803 // convention), which might be cluttered by the potential first
5804 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005805 //
5806 // TODO: Introduce a new runtime entry point taking the object
5807 // to test (instead of its class) as argument, and let it deal
5808 // with the read barrier issues. This will let us refactor this
5809 // case of the `switch` code as it was previously (with a direct
5810 // call to the runtime not using a type checking slow path).
5811 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005812 DCHECK(locations->OnlyCallsOnSlowPath());
5813 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5814 /* is_fatal */ false);
5815 codegen_->AddSlowPath(slow_path);
5816 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005817 if (zero.IsLinked()) {
5818 __ b(&done);
5819 }
5820 break;
5821 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005822 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005823
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005824 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005825 __ Bind(&zero);
5826 __ LoadImmediate(out, 0);
5827 }
5828
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005829 if (done.IsLinked()) {
5830 __ Bind(&done);
5831 }
5832
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005833 if (slow_path != nullptr) {
5834 __ Bind(slow_path->GetExitLabel());
5835 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005836}
5837
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005838void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005839 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5840 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5841
Roland Levillain3b359c72015-11-17 19:35:12 +00005842 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5843 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005844 case TypeCheckKind::kExactCheck:
5845 case TypeCheckKind::kAbstractClassCheck:
5846 case TypeCheckKind::kClassHierarchyCheck:
5847 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005848 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5849 LocationSummary::kCallOnSlowPath :
5850 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005851 break;
5852 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005853 case TypeCheckKind::kUnresolvedCheck:
5854 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005855 call_kind = LocationSummary::kCallOnSlowPath;
5856 break;
5857 }
5858
Roland Levillain3b359c72015-11-17 19:35:12 +00005859 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5860 locations->SetInAt(0, Location::RequiresRegister());
5861 locations->SetInAt(1, Location::RequiresRegister());
5862 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5863 locations->AddTemp(Location::RequiresRegister());
5864 // When read barriers are enabled, we need an additional temporary
5865 // register for some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005866 if (TypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005867 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005868 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005869}
5870
5871void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005872 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005873 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005874 Location obj_loc = locations->InAt(0);
5875 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005876 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005877 Location temp_loc = locations->GetTemp(0);
5878 Register temp = temp_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005879 Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005880 locations->GetTemp(1) :
5881 Location::NoLocation();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005882 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005883 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5884 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5885 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005886
Roland Levillain3b359c72015-11-17 19:35:12 +00005887 bool is_type_check_slow_path_fatal =
5888 (type_check_kind == TypeCheckKind::kExactCheck ||
5889 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5890 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5891 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5892 !instruction->CanThrowIntoCatchBlock();
5893 SlowPathCode* type_check_slow_path =
5894 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5895 is_type_check_slow_path_fatal);
5896 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005897
5898 Label done;
5899 // Avoid null check if we know obj is not null.
5900 if (instruction->MustDoNullCheck()) {
5901 __ CompareAndBranchIfZero(obj, &done);
5902 }
5903
Roland Levillain3b359c72015-11-17 19:35:12 +00005904 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005905 GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005906
Roland Levillain3b359c72015-11-17 19:35:12 +00005907 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005908 case TypeCheckKind::kExactCheck:
5909 case TypeCheckKind::kArrayCheck: {
5910 __ cmp(temp, ShifterOperand(cls));
5911 // Jump to slow path for throwing the exception or doing a
5912 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005913 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005914 break;
5915 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005916
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005917 case TypeCheckKind::kAbstractClassCheck: {
5918 // If the class is abstract, we eagerly fetch the super class of the
5919 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005920 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005921 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005922 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005923 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005924
5925 // If the class reference currently in `temp` is not null, jump
5926 // to the `compare_classes` label to compare it with the checked
5927 // class.
5928 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5929 // Otherwise, jump to the slow path to throw the exception.
5930 //
5931 // But before, move back the object's class into `temp` before
5932 // going into the slow path, as it has been overwritten in the
5933 // meantime.
5934 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005935 GenerateReferenceLoadTwoRegisters(
5936 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005937 __ b(type_check_slow_path->GetEntryLabel());
5938
5939 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005940 __ cmp(temp, ShifterOperand(cls));
5941 __ b(&loop, NE);
5942 break;
5943 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005944
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005945 case TypeCheckKind::kClassHierarchyCheck: {
5946 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005947 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005948 __ Bind(&loop);
5949 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005950 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005951
Roland Levillain3b359c72015-11-17 19:35:12 +00005952 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005953 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005954
5955 // If the class reference currently in `temp` is not null, jump
5956 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005957 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005958 // Otherwise, jump to the slow path to throw the exception.
5959 //
5960 // But before, move back the object's class into `temp` before
5961 // going into the slow path, as it has been overwritten in the
5962 // meantime.
5963 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005964 GenerateReferenceLoadTwoRegisters(
5965 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005966 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005967 break;
5968 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005969
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005970 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005971 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005972 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005973 __ cmp(temp, ShifterOperand(cls));
5974 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005975
5976 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005977 // /* HeapReference<Class> */ temp = temp->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005978 GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005979
5980 // If the component type is not null (i.e. the object is indeed
5981 // an array), jump to label `check_non_primitive_component_type`
5982 // to further check that this component type is not a primitive
5983 // type.
5984 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5985 // Otherwise, jump to the slow path to throw the exception.
5986 //
5987 // But before, move back the object's class into `temp` before
5988 // going into the slow path, as it has been overwritten in the
5989 // meantime.
5990 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005991 GenerateReferenceLoadTwoRegisters(
5992 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005993 __ b(type_check_slow_path->GetEntryLabel());
5994
5995 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005996 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005997 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5998 __ CompareAndBranchIfZero(temp, &done);
5999 // Same comment as above regarding `temp` and the slow path.
6000 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006001 GenerateReferenceLoadTwoRegisters(
6002 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00006003 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006004 break;
6005 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006006
Calin Juravle98893e12015-10-02 21:05:03 +01006007 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006008 case TypeCheckKind::kInterfaceCheck:
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006009 // We always go into the type check slow path for the unresolved
6010 // and interface check cases.
Roland Levillain3b359c72015-11-17 19:35:12 +00006011 //
6012 // We cannot directly call the CheckCast runtime entry point
6013 // without resorting to a type checking slow path here (i.e. by
6014 // calling InvokeRuntime directly), as it would require to
6015 // assign fixed registers for the inputs of this HInstanceOf
6016 // instruction (following the runtime calling convention), which
6017 // might be cluttered by the potential first read barrier
6018 // emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00006019 //
6020 // TODO: Introduce a new runtime entry point taking the object
6021 // to test (instead of its class) as argument, and let it deal
6022 // with the read barrier issues. This will let us refactor this
6023 // case of the `switch` code as it was previously (with a direct
6024 // call to the runtime not using a type checking slow path).
6025 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00006026 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00006027 break;
6028 }
6029 __ Bind(&done);
6030
Roland Levillain3b359c72015-11-17 19:35:12 +00006031 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00006032}
6033
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006034void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6035 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006036 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006037 InvokeRuntimeCallingConvention calling_convention;
6038 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6039}
6040
6041void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
6042 codegen_->InvokeRuntime(instruction->IsEnter()
6043 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
6044 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00006045 instruction->GetDexPc(),
6046 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00006047 if (instruction->IsEnter()) {
6048 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
6049 } else {
6050 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
6051 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00006052}
6053
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006054void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
6055void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
6056void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006057
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006058void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006059 LocationSummary* locations =
6060 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6061 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6062 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006063 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006064 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006065 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00006066 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006067}
6068
6069void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
6070 HandleBitwiseOperation(instruction);
6071}
6072
6073void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
6074 HandleBitwiseOperation(instruction);
6075}
6076
6077void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
6078 HandleBitwiseOperation(instruction);
6079}
6080
Artem Serov7fc63502016-02-09 17:15:29 +00006081
6082void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6083 LocationSummary* locations =
6084 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6085 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
6086 || instruction->GetResultType() == Primitive::kPrimLong);
6087
6088 locations->SetInAt(0, Location::RequiresRegister());
6089 locations->SetInAt(1, Location::RequiresRegister());
6090 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6091}
6092
6093void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
6094 LocationSummary* locations = instruction->GetLocations();
6095 Location first = locations->InAt(0);
6096 Location second = locations->InAt(1);
6097 Location out = locations->Out();
6098
6099 if (instruction->GetResultType() == Primitive::kPrimInt) {
6100 Register first_reg = first.AsRegister<Register>();
6101 ShifterOperand second_reg(second.AsRegister<Register>());
6102 Register out_reg = out.AsRegister<Register>();
6103
6104 switch (instruction->GetOpKind()) {
6105 case HInstruction::kAnd:
6106 __ bic(out_reg, first_reg, second_reg);
6107 break;
6108 case HInstruction::kOr:
6109 __ orn(out_reg, first_reg, second_reg);
6110 break;
6111 // There is no EON on arm.
6112 case HInstruction::kXor:
6113 default:
6114 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6115 UNREACHABLE();
6116 }
6117 return;
6118
6119 } else {
6120 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6121 Register first_low = first.AsRegisterPairLow<Register>();
6122 Register first_high = first.AsRegisterPairHigh<Register>();
6123 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6124 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6125 Register out_low = out.AsRegisterPairLow<Register>();
6126 Register out_high = out.AsRegisterPairHigh<Register>();
6127
6128 switch (instruction->GetOpKind()) {
6129 case HInstruction::kAnd:
6130 __ bic(out_low, first_low, second_low);
6131 __ bic(out_high, first_high, second_high);
6132 break;
6133 case HInstruction::kOr:
6134 __ orn(out_low, first_low, second_low);
6135 __ orn(out_high, first_high, second_high);
6136 break;
6137 // There is no EON on arm.
6138 case HInstruction::kXor:
6139 default:
6140 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
6141 UNREACHABLE();
6142 }
6143 }
6144}
6145
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006146void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
6147 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
6148 if (value == 0xffffffffu) {
6149 if (out != first) {
6150 __ mov(out, ShifterOperand(first));
6151 }
6152 return;
6153 }
6154 if (value == 0u) {
6155 __ mov(out, ShifterOperand(0));
6156 return;
6157 }
6158 ShifterOperand so;
6159 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
6160 __ and_(out, first, so);
6161 } else {
6162 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
6163 __ bic(out, first, ShifterOperand(~value));
6164 }
6165}
6166
6167void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
6168 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
6169 if (value == 0u) {
6170 if (out != first) {
6171 __ mov(out, ShifterOperand(first));
6172 }
6173 return;
6174 }
6175 if (value == 0xffffffffu) {
6176 __ mvn(out, ShifterOperand(0));
6177 return;
6178 }
6179 ShifterOperand so;
6180 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
6181 __ orr(out, first, so);
6182 } else {
6183 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
6184 __ orn(out, first, ShifterOperand(~value));
6185 }
6186}
6187
6188void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6189 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6190 if (value == 0u) {
6191 if (out != first) {
6192 __ mov(out, ShifterOperand(first));
6193 }
6194 return;
6195 }
6196 __ eor(out, first, ShifterOperand(value));
6197}
6198
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006199void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6200 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006201 Location first = locations->InAt(0);
6202 Location second = locations->InAt(1);
6203 Location out = locations->Out();
6204
6205 if (second.IsConstant()) {
6206 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6207 uint32_t value_low = Low32Bits(value);
6208 if (instruction->GetResultType() == Primitive::kPrimInt) {
6209 Register first_reg = first.AsRegister<Register>();
6210 Register out_reg = out.AsRegister<Register>();
6211 if (instruction->IsAnd()) {
6212 GenerateAndConst(out_reg, first_reg, value_low);
6213 } else if (instruction->IsOr()) {
6214 GenerateOrrConst(out_reg, first_reg, value_low);
6215 } else {
6216 DCHECK(instruction->IsXor());
6217 GenerateEorConst(out_reg, first_reg, value_low);
6218 }
6219 } else {
6220 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6221 uint32_t value_high = High32Bits(value);
6222 Register first_low = first.AsRegisterPairLow<Register>();
6223 Register first_high = first.AsRegisterPairHigh<Register>();
6224 Register out_low = out.AsRegisterPairLow<Register>();
6225 Register out_high = out.AsRegisterPairHigh<Register>();
6226 if (instruction->IsAnd()) {
6227 GenerateAndConst(out_low, first_low, value_low);
6228 GenerateAndConst(out_high, first_high, value_high);
6229 } else if (instruction->IsOr()) {
6230 GenerateOrrConst(out_low, first_low, value_low);
6231 GenerateOrrConst(out_high, first_high, value_high);
6232 } else {
6233 DCHECK(instruction->IsXor());
6234 GenerateEorConst(out_low, first_low, value_low);
6235 GenerateEorConst(out_high, first_high, value_high);
6236 }
6237 }
6238 return;
6239 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006240
6241 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006242 Register first_reg = first.AsRegister<Register>();
6243 ShifterOperand second_reg(second.AsRegister<Register>());
6244 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006245 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006246 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006247 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006248 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006249 } else {
6250 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006251 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006252 }
6253 } else {
6254 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006255 Register first_low = first.AsRegisterPairLow<Register>();
6256 Register first_high = first.AsRegisterPairHigh<Register>();
6257 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6258 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6259 Register out_low = out.AsRegisterPairLow<Register>();
6260 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006261 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006262 __ and_(out_low, first_low, second_low);
6263 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006264 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006265 __ orr(out_low, first_low, second_low);
6266 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006267 } else {
6268 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006269 __ eor(out_low, first_low, second_low);
6270 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006271 }
6272 }
6273}
6274
Roland Levillainc9285912015-12-18 10:38:42 +00006275void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
6276 Location out,
6277 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006278 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006279 Register out_reg = out.AsRegister<Register>();
6280 if (kEmitCompilerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006281 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006282 if (kUseBakerReadBarrier) {
6283 // Load with fast path based Baker's read barrier.
6284 // /* HeapReference<Object> */ out = *(out + offset)
6285 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006286 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006287 } else {
6288 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006289 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006290 // in the following move operation, as we will need it for the
6291 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006292 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006293 // /* HeapReference<Object> */ out = *(out + offset)
6294 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006295 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006296 }
6297 } else {
6298 // Plain load with no read barrier.
6299 // /* HeapReference<Object> */ out = *(out + offset)
6300 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6301 __ MaybeUnpoisonHeapReference(out_reg);
6302 }
6303}
6304
6305void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6306 Location out,
6307 Location obj,
6308 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006309 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006310 Register out_reg = out.AsRegister<Register>();
6311 Register obj_reg = obj.AsRegister<Register>();
6312 if (kEmitCompilerReadBarrier) {
6313 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006314 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006315 // Load with fast path based Baker's read barrier.
6316 // /* HeapReference<Object> */ out = *(obj + offset)
6317 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006318 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006319 } else {
6320 // Load with slow path based read barrier.
6321 // /* HeapReference<Object> */ out = *(obj + offset)
6322 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6323 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6324 }
6325 } else {
6326 // Plain load with no read barrier.
6327 // /* HeapReference<Object> */ out = *(obj + offset)
6328 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6329 __ MaybeUnpoisonHeapReference(out_reg);
6330 }
6331}
6332
6333void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6334 Location root,
6335 Register obj,
6336 uint32_t offset) {
6337 Register root_reg = root.AsRegister<Register>();
6338 if (kEmitCompilerReadBarrier) {
6339 if (kUseBakerReadBarrier) {
6340 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6341 // Baker's read barrier are used:
6342 //
6343 // root = obj.field;
6344 // if (Thread::Current()->GetIsGcMarking()) {
6345 // root = ReadBarrier::Mark(root)
6346 // }
6347
6348 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6349 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6350 static_assert(
6351 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6352 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6353 "have different sizes.");
6354 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6355 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6356 "have different sizes.");
6357
6358 // Slow path used to mark the GC root `root`.
6359 SlowPathCode* slow_path =
Roland Levillain02b75802016-07-13 11:54:35 +01006360 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root);
Roland Levillainc9285912015-12-18 10:38:42 +00006361 codegen_->AddSlowPath(slow_path);
6362
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006363 // IP = Thread::Current()->GetIsGcMarking()
Roland Levillainc9285912015-12-18 10:38:42 +00006364 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006365 kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmPointerSize>().Int32Value());
Roland Levillainc9285912015-12-18 10:38:42 +00006366 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6367 __ Bind(slow_path->GetExitLabel());
6368 } else {
6369 // GC root loaded through a slow path for read barriers other
6370 // than Baker's.
6371 // /* GcRoot<mirror::Object>* */ root = obj + offset
6372 __ AddConstant(root_reg, obj, offset);
6373 // /* mirror::Object* */ root = root->Read()
6374 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6375 }
6376 } else {
6377 // Plain GC root load with no read barrier.
6378 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6379 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6380 // Note that GC roots are not affected by heap poisoning, thus we
6381 // do not have to unpoison `root_reg` here.
6382 }
6383}
6384
6385void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6386 Location ref,
6387 Register obj,
6388 uint32_t offset,
6389 Location temp,
6390 bool needs_null_check) {
6391 DCHECK(kEmitCompilerReadBarrier);
6392 DCHECK(kUseBakerReadBarrier);
6393
6394 // /* HeapReference<Object> */ ref = *(obj + offset)
6395 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01006396 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00006397 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006398 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006399}
6400
6401void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6402 Location ref,
6403 Register obj,
6404 uint32_t data_offset,
6405 Location index,
6406 Location temp,
6407 bool needs_null_check) {
6408 DCHECK(kEmitCompilerReadBarrier);
6409 DCHECK(kUseBakerReadBarrier);
6410
Roland Levillainbfea3352016-06-23 13:48:47 +01006411 static_assert(
6412 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6413 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006414 // /* HeapReference<Object> */ ref =
6415 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01006416 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00006417 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006418 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006419}
6420
6421void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6422 Location ref,
6423 Register obj,
6424 uint32_t offset,
6425 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01006426 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00006427 Location temp,
6428 bool needs_null_check) {
6429 DCHECK(kEmitCompilerReadBarrier);
6430 DCHECK(kUseBakerReadBarrier);
6431
6432 // In slow path based read barriers, the read barrier call is
6433 // inserted after the original load. However, in fast path based
6434 // Baker's read barriers, we need to perform the load of
6435 // mirror::Object::monitor_ *before* the original reference load.
6436 // This load-load ordering is required by the read barrier.
6437 // The fast path/slow path (for Baker's algorithm) should look like:
6438 //
6439 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6440 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6441 // HeapReference<Object> ref = *src; // Original reference load.
6442 // bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6443 // if (is_gray) {
6444 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6445 // }
6446 //
6447 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006448 // slightly more complex as it performs additional checks that we do
6449 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00006450
6451 Register ref_reg = ref.AsRegister<Register>();
6452 Register temp_reg = temp.AsRegister<Register>();
6453 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6454
6455 // /* int32_t */ monitor = obj->monitor_
6456 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6457 if (needs_null_check) {
6458 MaybeRecordImplicitNullCheck(instruction);
6459 }
6460 // /* LockWord */ lock_word = LockWord(monitor)
6461 static_assert(sizeof(LockWord) == sizeof(int32_t),
6462 "art::LockWord and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006463
Vladimir Marko194bcfe2016-07-11 15:52:00 +01006464 // Introduce a dependency on the lock_word including the rb_state,
6465 // which shall prevent load-load reordering without using
Roland Levillainc9285912015-12-18 10:38:42 +00006466 // a memory barrier (which would be more expensive).
Vladimir Marko194bcfe2016-07-11 15:52:00 +01006467 // obj is unchanged by this operation, but its value now depends on temp_reg.
6468 __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
Roland Levillainc9285912015-12-18 10:38:42 +00006469
6470 // The actual reference load.
6471 if (index.IsValid()) {
Roland Levillainbfea3352016-06-23 13:48:47 +01006472 // Load types involving an "index": ArrayGet and
6473 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
6474 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00006475 if (index.IsConstant()) {
6476 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01006477 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006478 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6479 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01006480 // Handle the special case of the
6481 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use
6482 // a register pair as index ("long offset"), of which only the low
6483 // part contains data.
6484 Register index_reg = index.IsRegisterPair()
6485 ? index.AsRegisterPairLow<Register>()
6486 : index.AsRegister<Register>();
6487 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00006488 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6489 }
6490 } else {
6491 // /* HeapReference<Object> */ ref = *(obj + offset)
6492 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6493 }
6494
6495 // Object* ref = ref_addr->AsMirrorPtr()
6496 __ MaybeUnpoisonHeapReference(ref_reg);
6497
6498 // Slow path used to mark the object `ref` when it is gray.
6499 SlowPathCode* slow_path =
Roland Levillain02b75802016-07-13 11:54:35 +01006500 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
Roland Levillainc9285912015-12-18 10:38:42 +00006501 AddSlowPath(slow_path);
6502
6503 // if (rb_state == ReadBarrier::gray_ptr_)
6504 // ref = ReadBarrier::Mark(ref);
Vladimir Marko194bcfe2016-07-11 15:52:00 +01006505 // Given the numeric representation, it's enough to check the low bit of the
6506 // rb_state. We do that by shifting the bit out of the lock word with LSRS
6507 // which can be a 16-bit instruction unlike the TST immediate.
6508 static_assert(ReadBarrier::white_ptr_ == 0, "Expecting white to have value 0");
6509 static_assert(ReadBarrier::gray_ptr_ == 1, "Expecting gray to have value 1");
6510 static_assert(ReadBarrier::black_ptr_ == 2, "Expecting black to have value 2");
6511 __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
6512 __ b(slow_path->GetEntryLabel(), CS); // Carry flag is the last bit shifted out by LSRS.
Roland Levillainc9285912015-12-18 10:38:42 +00006513 __ Bind(slow_path->GetExitLabel());
6514}
6515
6516void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6517 Location out,
6518 Location ref,
6519 Location obj,
6520 uint32_t offset,
6521 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006522 DCHECK(kEmitCompilerReadBarrier);
6523
Roland Levillainc9285912015-12-18 10:38:42 +00006524 // Insert a slow path based read barrier *after* the reference load.
6525 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006526 // If heap poisoning is enabled, the unpoisoning of the loaded
6527 // reference will be carried out by the runtime within the slow
6528 // path.
6529 //
6530 // Note that `ref` currently does not get unpoisoned (when heap
6531 // poisoning is enabled), which is alright as the `ref` argument is
6532 // not used by the artReadBarrierSlow entry point.
6533 //
6534 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6535 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6536 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6537 AddSlowPath(slow_path);
6538
Roland Levillain3b359c72015-11-17 19:35:12 +00006539 __ b(slow_path->GetEntryLabel());
6540 __ Bind(slow_path->GetExitLabel());
6541}
6542
Roland Levillainc9285912015-12-18 10:38:42 +00006543void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6544 Location out,
6545 Location ref,
6546 Location obj,
6547 uint32_t offset,
6548 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006549 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00006550 // Baker's read barriers shall be handled by the fast path
6551 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6552 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006553 // If heap poisoning is enabled, unpoisoning will be taken care of
6554 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00006555 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00006556 } else if (kPoisonHeapReferences) {
6557 __ UnpoisonHeapReference(out.AsRegister<Register>());
6558 }
6559}
6560
Roland Levillainc9285912015-12-18 10:38:42 +00006561void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6562 Location out,
6563 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006564 DCHECK(kEmitCompilerReadBarrier);
6565
Roland Levillainc9285912015-12-18 10:38:42 +00006566 // Insert a slow path based read barrier *after* the GC root load.
6567 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006568 // Note that GC roots are not affected by heap poisoning, so we do
6569 // not need to do anything special for this here.
6570 SlowPathCode* slow_path =
6571 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6572 AddSlowPath(slow_path);
6573
Roland Levillain3b359c72015-11-17 19:35:12 +00006574 __ b(slow_path->GetEntryLabel());
6575 __ Bind(slow_path->GetExitLabel());
6576}
6577
Vladimir Markodc151b22015-10-15 18:02:30 +01006578HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6579 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6580 MethodReference target_method) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006581 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6582 // We disable pc-relative load when there is an irreducible loop, as the optimization
6583 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006584 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6585 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006586 if (GetGraph()->HasIrreducibleLoops() &&
6587 (dispatch_info.method_load_kind ==
6588 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6589 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6590 }
6591
6592 if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
Vladimir Markodc151b22015-10-15 18:02:30 +01006593 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6594 if (&outer_dex_file != target_method.dex_file) {
6595 // Calls across dex files are more likely to exceed the available BL range,
6596 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6597 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6598 (desired_dispatch_info.method_load_kind ==
6599 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6600 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6601 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6602 return HInvokeStaticOrDirect::DispatchInfo {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006603 dispatch_info.method_load_kind,
Vladimir Markodc151b22015-10-15 18:02:30 +01006604 code_ptr_location,
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006605 dispatch_info.method_load_data,
Vladimir Markodc151b22015-10-15 18:02:30 +01006606 0u
6607 };
6608 }
6609 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006610 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01006611}
6612
Vladimir Markob4536b72015-11-24 13:45:23 +00006613Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6614 Register temp) {
6615 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6616 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6617 if (!invoke->GetLocations()->Intrinsified()) {
6618 return location.AsRegister<Register>();
6619 }
6620 // For intrinsics we allow any location, so it may be on the stack.
6621 if (!location.IsRegister()) {
6622 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6623 return temp;
6624 }
6625 // For register locations, check if the register was saved. If so, get it from the stack.
6626 // Note: There is a chance that the register was saved but not overwritten, so we could
6627 // save one load. However, since this is just an intrinsic slow path we prefer this
6628 // simple and more robust approach rather that trying to determine if that's the case.
6629 SlowPathCode* slow_path = GetCurrentSlowPath();
6630 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6631 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6632 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6633 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6634 return temp;
6635 }
6636 return location.AsRegister<Register>();
6637}
6638
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006639void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006640 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006641 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006642 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6643 // LR = code address from literal pool with link-time patch.
6644 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006645 break;
6646 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6647 // LR = invoke->GetDirectCodePtr();
6648 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006649 break;
6650 default:
6651 break;
6652 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006653
Vladimir Marko58155012015-08-19 12:49:41 +00006654 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6655 switch (invoke->GetMethodLoadKind()) {
6656 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6657 // temp = thread->string_init_entrypoint
6658 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6659 break;
6660 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006661 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006662 break;
6663 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6664 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6665 break;
6666 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6667 __ LoadLiteral(temp.AsRegister<Register>(),
6668 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6669 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006670 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6671 HArmDexCacheArraysBase* base =
6672 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6673 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6674 temp.AsRegister<Register>());
6675 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6676 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6677 break;
6678 }
Vladimir Marko58155012015-08-19 12:49:41 +00006679 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006680 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006681 Register method_reg;
6682 Register reg = temp.AsRegister<Register>();
6683 if (current_method.IsRegister()) {
6684 method_reg = current_method.AsRegister<Register>();
6685 } else {
6686 DCHECK(invoke->GetLocations()->Intrinsified());
6687 DCHECK(!current_method.IsValid());
6688 method_reg = reg;
6689 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6690 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006691 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6692 __ LoadFromOffset(kLoadWord,
6693 reg,
6694 method_reg,
6695 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01006696 // temp = temp[index_in_cache];
6697 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6698 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00006699 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6700 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006701 }
Vladimir Marko58155012015-08-19 12:49:41 +00006702 }
6703
6704 switch (invoke->GetCodePtrLocation()) {
6705 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6706 __ bl(GetFrameEntryLabel());
6707 break;
6708 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006709 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006710 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006711 // Arbitrarily branch to the BL itself, override at link time.
6712 __ bl(&relative_call_patches_.back().label);
6713 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006714 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6715 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6716 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006717 // LR()
6718 __ blx(LR);
6719 break;
6720 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6721 // LR = callee_method->entry_point_from_quick_compiled_code_
6722 __ LoadFromOffset(
6723 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07006724 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00006725 // LR()
6726 __ blx(LR);
6727 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006728 }
6729
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006730 DCHECK(!IsLeafMethod());
6731}
6732
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006733void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6734 Register temp = temp_location.AsRegister<Register>();
6735 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6736 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006737
6738 // Use the calling convention instead of the location of the receiver, as
6739 // intrinsics may have put the receiver in a different register. In the intrinsics
6740 // slow path, the arguments have been moved to the right place, so here we are
6741 // guaranteed that the receiver is the first register of the calling convention.
6742 InvokeDexCallingConvention calling_convention;
6743 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006744 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006745 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006746 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006747 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006748 // Instead of simply (possibly) unpoisoning `temp` here, we should
6749 // emit a read barrier for the previous class reference load.
6750 // However this is not required in practice, as this is an
6751 // intermediate/temporary reference and because the current
6752 // concurrent copying collector keeps the from-space memory
6753 // intact/accessible until the end of the marking phase (the
6754 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006755 __ MaybeUnpoisonHeapReference(temp);
6756 // temp = temp->GetMethodAt(method_offset);
6757 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006758 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006759 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6760 // LR = temp->GetEntryPoint();
6761 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6762 // LR();
6763 __ blx(LR);
6764}
6765
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006766CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6767 const DexFile& dex_file, uint32_t string_index) {
6768 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6769}
6770
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006771CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
6772 const DexFile& dex_file, uint32_t type_index) {
6773 return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
6774}
6775
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006776CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6777 const DexFile& dex_file, uint32_t element_offset) {
6778 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6779}
6780
6781CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6782 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6783 patches->emplace_back(dex_file, offset_or_index);
6784 return &patches->back();
6785}
6786
6787Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6788 uint32_t string_index) {
6789 return boot_image_string_patches_.GetOrCreate(
6790 StringReference(&dex_file, string_index),
6791 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6792}
6793
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006794Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
6795 uint32_t type_index) {
6796 return boot_image_type_patches_.GetOrCreate(
6797 TypeReference(&dex_file, type_index),
6798 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6799}
6800
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006801Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6802 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6803 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6804 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6805}
6806
6807Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6808 return DeduplicateUint32Literal(address, &uint32_literals_);
6809}
6810
Vladimir Marko58155012015-08-19 12:49:41 +00006811void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6812 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006813 size_t size =
6814 method_patches_.size() +
6815 call_patches_.size() +
6816 relative_call_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006817 /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6818 boot_image_string_patches_.size() +
6819 /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006820 boot_image_type_patches_.size() +
6821 /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006822 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006823 linker_patches->reserve(size);
6824 for (const auto& entry : method_patches_) {
6825 const MethodReference& target_method = entry.first;
6826 Literal* literal = entry.second;
6827 DCHECK(literal->GetLabel()->IsBound());
6828 uint32_t literal_offset = literal->GetLabel()->Position();
6829 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6830 target_method.dex_file,
6831 target_method.dex_method_index));
6832 }
6833 for (const auto& entry : call_patches_) {
6834 const MethodReference& target_method = entry.first;
6835 Literal* literal = entry.second;
6836 DCHECK(literal->GetLabel()->IsBound());
6837 uint32_t literal_offset = literal->GetLabel()->Position();
6838 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6839 target_method.dex_file,
6840 target_method.dex_method_index));
6841 }
6842 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6843 uint32_t literal_offset = info.label.Position();
6844 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6845 info.target_method.dex_file,
6846 info.target_method.dex_method_index));
6847 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006848 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6849 const DexFile& dex_file = info.target_dex_file;
6850 size_t base_element_offset = info.offset_or_index;
6851 DCHECK(info.add_pc_label.IsBound());
6852 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006853 // Add MOVW patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006854 DCHECK(info.movw_label.IsBound());
6855 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006856 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6857 &dex_file,
6858 add_pc_offset,
6859 base_element_offset));
6860 // Add MOVT patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006861 DCHECK(info.movt_label.IsBound());
6862 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006863 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6864 &dex_file,
6865 add_pc_offset,
6866 base_element_offset));
6867 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006868 for (const auto& entry : boot_image_string_patches_) {
6869 const StringReference& target_string = entry.first;
6870 Literal* literal = entry.second;
6871 DCHECK(literal->GetLabel()->IsBound());
6872 uint32_t literal_offset = literal->GetLabel()->Position();
6873 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6874 target_string.dex_file,
6875 target_string.string_index));
6876 }
6877 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6878 const DexFile& dex_file = info.target_dex_file;
6879 uint32_t string_index = info.offset_or_index;
6880 DCHECK(info.add_pc_label.IsBound());
6881 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6882 // Add MOVW patch.
6883 DCHECK(info.movw_label.IsBound());
6884 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6885 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6886 &dex_file,
6887 add_pc_offset,
6888 string_index));
6889 // Add MOVT patch.
6890 DCHECK(info.movt_label.IsBound());
6891 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6892 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6893 &dex_file,
6894 add_pc_offset,
6895 string_index));
6896 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006897 for (const auto& entry : boot_image_type_patches_) {
6898 const TypeReference& target_type = entry.first;
6899 Literal* literal = entry.second;
6900 DCHECK(literal->GetLabel()->IsBound());
6901 uint32_t literal_offset = literal->GetLabel()->Position();
6902 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
6903 target_type.dex_file,
6904 target_type.type_index));
6905 }
6906 for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
6907 const DexFile& dex_file = info.target_dex_file;
6908 uint32_t type_index = info.offset_or_index;
6909 DCHECK(info.add_pc_label.IsBound());
6910 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6911 // Add MOVW patch.
6912 DCHECK(info.movw_label.IsBound());
6913 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6914 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset,
6915 &dex_file,
6916 add_pc_offset,
6917 type_index));
6918 // Add MOVT patch.
6919 DCHECK(info.movt_label.IsBound());
6920 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6921 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset,
6922 &dex_file,
6923 add_pc_offset,
6924 type_index));
6925 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006926 for (const auto& entry : boot_image_address_patches_) {
6927 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6928 Literal* literal = entry.second;
6929 DCHECK(literal->GetLabel()->IsBound());
6930 uint32_t literal_offset = literal->GetLabel()->Position();
6931 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6932 }
6933}
6934
6935Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6936 return map->GetOrCreate(
6937 value,
6938 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00006939}
6940
6941Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6942 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006943 return map->GetOrCreate(
6944 target_method,
6945 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00006946}
6947
6948Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6949 return DeduplicateMethodLiteral(target_method, &method_patches_);
6950}
6951
6952Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6953 return DeduplicateMethodLiteral(target_method, &call_patches_);
6954}
6955
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03006956void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6957 LocationSummary* locations =
6958 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6959 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6960 Location::RequiresRegister());
6961 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6962 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6963 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6964}
6965
6966void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6967 LocationSummary* locations = instr->GetLocations();
6968 Register res = locations->Out().AsRegister<Register>();
6969 Register accumulator =
6970 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6971 Register mul_left =
6972 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6973 Register mul_right =
6974 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6975
6976 if (instr->GetOpKind() == HInstruction::kAdd) {
6977 __ mla(res, mul_left, mul_right, accumulator);
6978 } else {
6979 __ mls(res, mul_left, mul_right, accumulator);
6980 }
6981}
6982
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006983void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006984 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006985 LOG(FATAL) << "Unreachable";
6986}
6987
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006988void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006989 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006990 LOG(FATAL) << "Unreachable";
6991}
6992
Mark Mendellfe57faa2015-09-18 09:26:15 -04006993// Simple implementation of packed switch - generate cascaded compare/jumps.
6994void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6995 LocationSummary* locations =
6996 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6997 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006998 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006999 codegen_->GetAssembler()->IsThumb()) {
7000 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
7001 if (switch_instr->GetStartValue() != 0) {
7002 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
7003 }
7004 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007005}
7006
7007void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7008 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007009 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04007010 LocationSummary* locations = switch_instr->GetLocations();
7011 Register value_reg = locations->InAt(0).AsRegister<Register>();
7012 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7013
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007014 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007015 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007016 Register temp_reg = IP;
7017 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
7018 // the immediate, because IP is used as the destination register. For the other
7019 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
7020 // and they can be encoded in the instruction without making use of IP register.
7021 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
7022
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007023 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007024 // Jump to successors[0] if value == lower_bound.
7025 __ b(codegen_->GetLabelOf(successors[0]), EQ);
7026 int32_t last_index = 0;
7027 for (; num_entries - last_index > 2; last_index += 2) {
7028 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
7029 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
7030 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
7031 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
7032 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
7033 }
7034 if (num_entries - last_index == 2) {
7035 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00007036 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00007037 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007038 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04007039
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07007040 // And the default for any other value.
7041 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
7042 __ b(codegen_->GetLabelOf(default_block));
7043 }
7044 } else {
7045 // Create a table lookup.
7046 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
7047
7048 // Materialize a pointer to the switch table
7049 std::vector<Label*> labels(num_entries);
7050 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
7051 for (uint32_t i = 0; i < num_entries; i++) {
7052 labels[i] = codegen_->GetLabelOf(successors[i]);
7053 }
7054 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
7055
7056 // Remove the bias.
7057 Register key_reg;
7058 if (lower_bound != 0) {
7059 key_reg = locations->GetTemp(1).AsRegister<Register>();
7060 __ AddConstant(key_reg, value_reg, -lower_bound);
7061 } else {
7062 key_reg = value_reg;
7063 }
7064
7065 // Check whether the value is in the table, jump to default block if not.
7066 __ CmpConstant(key_reg, num_entries - 1);
7067 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
7068
7069 // Load the displacement from the table.
7070 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
7071
7072 // Dispatch is a direct add to the PC (for Thumb2).
7073 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04007074 }
7075}
7076
Vladimir Markob4536b72015-11-24 13:45:23 +00007077void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7078 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7079 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00007080}
7081
7082void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
7083 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007084 CodeGeneratorARM::PcRelativePatchInfo* labels =
7085 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00007086 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007087 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007088 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007089 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00007090 __ BindTrackedLabel(&labels->add_pc_label);
7091 __ add(base_reg, base_reg, ShifterOperand(PC));
7092}
7093
Andreas Gampe85b62f22015-09-09 13:15:38 -07007094void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
7095 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00007096 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07007097 return;
7098 }
7099
7100 DCHECK_NE(type, Primitive::kPrimVoid);
7101
7102 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
7103 if (return_loc.Equals(trg)) {
7104 return;
7105 }
7106
7107 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
7108 // with the last branch.
7109 if (type == Primitive::kPrimLong) {
7110 HParallelMove parallel_move(GetGraph()->GetArena());
7111 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
7112 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
7113 GetMoveResolver()->EmitNativeCode(&parallel_move);
7114 } else if (type == Primitive::kPrimDouble) {
7115 HParallelMove parallel_move(GetGraph()->GetArena());
7116 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
7117 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
7118 GetMoveResolver()->EmitNativeCode(&parallel_move);
7119 } else {
7120 // Let the parallel move resolver take care of all of this.
7121 HParallelMove parallel_move(GetGraph()->GetArena());
7122 parallel_move.AddMove(return_loc, trg, type, nullptr);
7123 GetMoveResolver()->EmitNativeCode(&parallel_move);
7124 }
7125}
7126
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007127void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
7128 LocationSummary* locations =
7129 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7130 locations->SetInAt(0, Location::RequiresRegister());
7131 locations->SetOut(Location::RequiresRegister());
7132}
7133
7134void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
7135 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00007136 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007137 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007138 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007139 __ LoadFromOffset(kLoadWord,
7140 locations->Out().AsRegister<Register>(),
7141 locations->InAt(0).AsRegister<Register>(),
7142 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007143 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007144 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007145 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007146 __ LoadFromOffset(kLoadWord,
7147 locations->Out().AsRegister<Register>(),
7148 locations->InAt(0).AsRegister<Register>(),
7149 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
7150 __ LoadFromOffset(kLoadWord,
7151 locations->Out().AsRegister<Register>(),
7152 locations->Out().AsRegister<Register>(),
7153 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007154 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007155}
7156
Roland Levillain4d027112015-07-01 15:41:14 +01007157#undef __
7158#undef QUICK_ENTRY_POINT
7159
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00007160} // namespace arm
7161} // namespace art