blob: f5befa65c1ef35b6e3636bdd22c70b8d6603b564 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Calin Juravle34166012014-12-19 17:22:29 +000019#include "arch/arm/instruction_set_features_arm.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "art_method.h"
Zheng Xuc6667102015-05-15 16:08:45 +080021#include "code_generator_utils.h"
Vladimir Marko58155012015-08-19 12:49:41 +000022#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070023#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010024#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080025#include "intrinsics.h"
26#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070027#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070028#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070029#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010030#include "utils/arm/assembler_arm.h"
31#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000032#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010033#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010036
Roland Levillain3b359c72015-11-17 19:35:12 +000037template<class MirrorType>
38class GcRoot;
39
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040namespace arm {
41
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000042static bool ExpectedPairLayout(Location location) {
43 // We expected this for both core and fpu register pairs.
44 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
45}
46
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010047static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010048static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010049
David Brazdil58282f42016-01-14 12:45:10 +000050static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000051static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070052 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000053static constexpr SRegister kFpuCalleeSaves[] =
54 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010055
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000056// D31 cannot be split into two S registers, and the register allocator only works on
57// S registers. Therefore there is no need to block it.
58static constexpr DRegister DTMP = D31;
59
Vladimir Markof3e0ee22015-12-17 15:23:13 +000060static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070061
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -070062// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
63#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010064#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Andreas Gampe85b62f22015-09-09 13:15:38 -070066class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000068 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010069
Alexandre Rames67555f72014-11-18 10:55:16 +000070 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010071 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010072 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000073 if (instruction_->CanThrowIntoCatchBlock()) {
74 // Live registers will be restored in the catch block if caught.
75 SaveLiveRegisters(codegen, instruction_->GetLocations());
76 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010077 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000078 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000079 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080 }
81
Alexandre Rames8158f282015-08-07 10:26:17 +010082 bool IsFatal() const OVERRIDE { return true; }
83
Alexandre Rames9931f312015-06-19 14:47:01 +010084 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
85
Nicolas Geoffraye5038322014-07-04 09:41:32 +010086 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010087 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
88};
89
Andreas Gampe85b62f22015-09-09 13:15:38 -070090class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000091 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000092 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +000093
Alexandre Rames67555f72014-11-18 10:55:16 +000094 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000095 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
96 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000097 if (instruction_->CanThrowIntoCatchBlock()) {
98 // Live registers will be restored in the catch block if caught.
99 SaveLiveRegisters(codegen, instruction_->GetLocations());
100 }
Calin Juravled0d48522014-11-04 16:40:20 +0000101 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000102 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000103 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000104 }
105
Alexandre Rames8158f282015-08-07 10:26:17 +0100106 bool IsFatal() const OVERRIDE { return true; }
107
Alexandre Rames9931f312015-06-19 14:47:01 +0100108 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
109
Calin Juravled0d48522014-11-04 16:40:20 +0000110 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000111 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
112};
113
Andreas Gampe85b62f22015-09-09 13:15:38 -0700114class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000115 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000116 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000117 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000118
Alexandre Rames67555f72014-11-18 10:55:16 +0000119 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100120 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000122 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100123 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000124 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000125 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000126 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100127 if (successor_ == nullptr) {
128 __ b(GetReturnLabel());
129 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100130 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100131 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132 }
133
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100134 Label* GetReturnLabel() {
135 DCHECK(successor_ == nullptr);
136 return &return_label_;
137 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100139 HBasicBlock* GetSuccessor() const {
140 return successor_;
141 }
142
Alexandre Rames9931f312015-06-19 14:47:01 +0100143 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
144
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000145 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100146 // If not null, the block to branch to after the suspend check.
147 HBasicBlock* const successor_;
148
149 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000150 Label return_label_;
151
152 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
153};
154
Andreas Gampe85b62f22015-09-09 13:15:38 -0700155class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100157 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000158 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100159
Alexandre Rames67555f72014-11-18 10:55:16 +0000160 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100161 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100162 LocationSummary* locations = instruction_->GetLocations();
163
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100164 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000165 if (instruction_->CanThrowIntoCatchBlock()) {
166 // Live registers will be restored in the catch block if caught.
167 SaveLiveRegisters(codegen, instruction_->GetLocations());
168 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000169 // We're moving two locations to locations that could overlap, so we need a parallel
170 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100171 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000172 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100173 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000174 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100175 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100176 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100177 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
178 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100179 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000180 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000181 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100182 }
183
Alexandre Rames8158f282015-08-07 10:26:17 +0100184 bool IsFatal() const OVERRIDE { return true; }
185
Alexandre Rames9931f312015-06-19 14:47:01 +0100186 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
187
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100188 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100189 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
190};
191
Andreas Gampe85b62f22015-09-09 13:15:38 -0700192class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100193 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000194 LoadClassSlowPathARM(HLoadClass* cls,
195 HInstruction* at,
196 uint32_t dex_pc,
197 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000198 : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000199 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
200 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100201
Alexandre Rames67555f72014-11-18 10:55:16 +0000202 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000203 LocationSummary* locations = at_->GetLocations();
204
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100205 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
206 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000207 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100209 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000211 int32_t entry_point_offset = do_clinit_
212 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
213 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000214 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000215 if (do_clinit_) {
216 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
217 } else {
218 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
219 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000220
221 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000222 Location out = locations->Out();
223 if (out.IsValid()) {
224 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
226 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000227 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228 __ b(GetExitLabel());
229 }
230
Alexandre Rames9931f312015-06-19 14:47:01 +0100231 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
232
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100233 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000234 // The class this slow path will load.
235 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100236
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 // The instruction where this slow path is happening.
238 // (Might be the load class or an initialization check).
239 HInstruction* const at_;
240
241 // The dex PC of `at_`.
242 const uint32_t dex_pc_;
243
244 // Whether to initialize the class.
245 const bool do_clinit_;
246
247 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100248};
249
Andreas Gampe85b62f22015-09-09 13:15:38 -0700250class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000251 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000252 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000253
Alexandre Rames67555f72014-11-18 10:55:16 +0000254 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000255 LocationSummary* locations = instruction_->GetLocations();
256 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
257
258 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
259 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000260 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000261
262 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000263 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
264 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000265 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000266 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000267 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000268 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
269
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000270 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000271 __ b(GetExitLabel());
272 }
273
Alexandre Rames9931f312015-06-19 14:47:01 +0100274 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
275
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000276 private:
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000277 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
278};
279
Andreas Gampe85b62f22015-09-09 13:15:38 -0700280class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000281 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000282 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000283 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284
Alexandre Rames67555f72014-11-18 10:55:16 +0000285 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100287 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
288 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000289 DCHECK(instruction_->IsCheckCast()
290 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000291
292 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
293 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000294
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000295 if (!is_fatal_) {
296 SaveLiveRegisters(codegen, locations);
297 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000298
299 // We're moving two locations to locations that could overlap, so we need a parallel
300 // move resolver.
301 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000302 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100303 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000304 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100305 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100306 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100307 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
308 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000309
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000310 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100311 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
312 instruction_,
313 instruction_->GetDexPc(),
314 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000315 CheckEntrypointTypes<
316 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000317 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
318 } else {
319 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100320 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
321 instruction_,
322 instruction_->GetDexPc(),
323 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000324 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000325 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000326
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000327 if (!is_fatal_) {
328 RestoreLiveRegisters(codegen, locations);
329 __ b(GetExitLabel());
330 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000331 }
332
Alexandre Rames9931f312015-06-19 14:47:01 +0100333 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
334
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000335 bool IsFatal() const OVERRIDE { return is_fatal_; }
336
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000337 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000338 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000339
340 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
341};
342
Andreas Gampe85b62f22015-09-09 13:15:38 -0700343class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700344 public:
Aart Bik42249c32016-01-07 15:33:50 -0800345 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000346 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700347
348 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800349 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700350 __ Bind(GetEntryLabel());
351 SaveLiveRegisters(codegen, instruction_->GetLocations());
Aart Bik42249c32016-01-07 15:33:50 -0800352 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
353 instruction_,
354 instruction_->GetDexPc(),
355 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000356 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700357 }
358
Alexandre Rames9931f312015-06-19 14:47:01 +0100359 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
360
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700361 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700362 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
363};
364
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100365class ArraySetSlowPathARM : public SlowPathCode {
366 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000367 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100368
369 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
370 LocationSummary* locations = instruction_->GetLocations();
371 __ Bind(GetEntryLabel());
372 SaveLiveRegisters(codegen, locations);
373
374 InvokeRuntimeCallingConvention calling_convention;
375 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
376 parallel_move.AddMove(
377 locations->InAt(0),
378 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
379 Primitive::kPrimNot,
380 nullptr);
381 parallel_move.AddMove(
382 locations->InAt(1),
383 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
384 Primitive::kPrimInt,
385 nullptr);
386 parallel_move.AddMove(
387 locations->InAt(2),
388 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
389 Primitive::kPrimNot,
390 nullptr);
391 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
392
393 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
394 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
395 instruction_,
396 instruction_->GetDexPc(),
397 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000398 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100399 RestoreLiveRegisters(codegen, locations);
400 __ b(GetExitLabel());
401 }
402
403 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
404
405 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100406 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
407};
408
Roland Levillainc9285912015-12-18 10:38:42 +0000409// Slow path marking an object during a read barrier.
410class ReadBarrierMarkSlowPathARM : public SlowPathCode {
411 public:
412 ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location out, Location obj)
David Srbecky9cd6d372016-02-09 15:24:47 +0000413 : SlowPathCode(instruction), out_(out), obj_(obj) {
Roland Levillainc9285912015-12-18 10:38:42 +0000414 DCHECK(kEmitCompilerReadBarrier);
415 }
416
417 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
418
419 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
420 LocationSummary* locations = instruction_->GetLocations();
421 Register reg_out = out_.AsRegister<Register>();
422 DCHECK(locations->CanCall());
423 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
424 DCHECK(instruction_->IsInstanceFieldGet() ||
425 instruction_->IsStaticFieldGet() ||
426 instruction_->IsArrayGet() ||
427 instruction_->IsLoadClass() ||
428 instruction_->IsLoadString() ||
429 instruction_->IsInstanceOf() ||
430 instruction_->IsCheckCast())
431 << "Unexpected instruction in read barrier marking slow path: "
432 << instruction_->DebugName();
433
434 __ Bind(GetEntryLabel());
435 SaveLiveRegisters(codegen, locations);
436
437 InvokeRuntimeCallingConvention calling_convention;
438 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
439 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
440 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
441 instruction_,
442 instruction_->GetDexPc(),
443 this);
444 CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
445 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
446
447 RestoreLiveRegisters(codegen, locations);
448 __ b(GetExitLabel());
449 }
450
451 private:
Roland Levillainc9285912015-12-18 10:38:42 +0000452 const Location out_;
453 const Location obj_;
454
455 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
456};
457
Roland Levillain3b359c72015-11-17 19:35:12 +0000458// Slow path generating a read barrier for a heap reference.
459class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
460 public:
461 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
462 Location out,
463 Location ref,
464 Location obj,
465 uint32_t offset,
466 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000467 : SlowPathCode(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000468 out_(out),
469 ref_(ref),
470 obj_(obj),
471 offset_(offset),
472 index_(index) {
473 DCHECK(kEmitCompilerReadBarrier);
474 // If `obj` is equal to `out` or `ref`, it means the initial object
475 // has been overwritten by (or after) the heap object reference load
476 // to be instrumented, e.g.:
477 //
478 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000479 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000480 //
481 // In that case, we have lost the information about the original
482 // object, and the emitted read barrier cannot work properly.
483 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
484 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
485 }
486
487 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
488 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
489 LocationSummary* locations = instruction_->GetLocations();
490 Register reg_out = out_.AsRegister<Register>();
491 DCHECK(locations->CanCall());
492 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
493 DCHECK(!instruction_->IsInvoke() ||
494 (instruction_->IsInvokeStaticOrDirect() &&
Roland Levillainc9285912015-12-18 10:38:42 +0000495 instruction_->GetLocations()->Intrinsified()))
496 << "Unexpected instruction in read barrier for heap reference slow path: "
497 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000498
499 __ Bind(GetEntryLabel());
500 SaveLiveRegisters(codegen, locations);
501
502 // We may have to change the index's value, but as `index_` is a
503 // constant member (like other "inputs" of this slow path),
504 // introduce a copy of it, `index`.
505 Location index = index_;
506 if (index_.IsValid()) {
507 // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
508 if (instruction_->IsArrayGet()) {
509 // Compute the actual memory offset and store it in `index`.
510 Register index_reg = index_.AsRegister<Register>();
511 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
512 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
513 // We are about to change the value of `index_reg` (see the
514 // calls to art::arm::Thumb2Assembler::Lsl and
515 // art::arm::Thumb2Assembler::AddConstant below), but it has
516 // not been saved by the previous call to
517 // art::SlowPathCode::SaveLiveRegisters, as it is a
518 // callee-save register --
519 // art::SlowPathCode::SaveLiveRegisters does not consider
520 // callee-save registers, as it has been designed with the
521 // assumption that callee-save registers are supposed to be
522 // handled by the called function. So, as a callee-save
523 // register, `index_reg` _would_ eventually be saved onto
524 // the stack, but it would be too late: we would have
525 // changed its value earlier. Therefore, we manually save
526 // it here into another freely available register,
527 // `free_reg`, chosen of course among the caller-save
528 // registers (as a callee-save `free_reg` register would
529 // exhibit the same problem).
530 //
531 // Note we could have requested a temporary register from
532 // the register allocator instead; but we prefer not to, as
533 // this is a slow path, and we know we can find a
534 // caller-save register that is available.
535 Register free_reg = FindAvailableCallerSaveRegister(codegen);
536 __ Mov(free_reg, index_reg);
537 index_reg = free_reg;
538 index = Location::RegisterLocation(index_reg);
539 } else {
540 // The initial register stored in `index_` has already been
541 // saved in the call to art::SlowPathCode::SaveLiveRegisters
542 // (as it is not a callee-save register), so we can freely
543 // use it.
544 }
545 // Shifting the index value contained in `index_reg` by the scale
546 // factor (2) cannot overflow in practice, as the runtime is
547 // unable to allocate object arrays with a size larger than
548 // 2^26 - 1 (that is, 2^28 - 4 bytes).
549 __ Lsl(index_reg, index_reg, TIMES_4);
550 static_assert(
551 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
552 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
553 __ AddConstant(index_reg, index_reg, offset_);
554 } else {
555 DCHECK(instruction_->IsInvoke());
556 DCHECK(instruction_->GetLocations()->Intrinsified());
557 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
558 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
559 << instruction_->AsInvoke()->GetIntrinsic();
560 DCHECK_EQ(offset_, 0U);
561 DCHECK(index_.IsRegisterPair());
562 // UnsafeGet's offset location is a register pair, the low
563 // part contains the correct offset.
564 index = index_.ToLow();
565 }
566 }
567
568 // We're moving two or three locations to locations that could
569 // overlap, so we need a parallel move resolver.
570 InvokeRuntimeCallingConvention calling_convention;
571 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
572 parallel_move.AddMove(ref_,
573 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
574 Primitive::kPrimNot,
575 nullptr);
576 parallel_move.AddMove(obj_,
577 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
578 Primitive::kPrimNot,
579 nullptr);
580 if (index.IsValid()) {
581 parallel_move.AddMove(index,
582 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
583 Primitive::kPrimInt,
584 nullptr);
585 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
586 } else {
587 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
588 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
589 }
590 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
591 instruction_,
592 instruction_->GetDexPc(),
593 this);
594 CheckEntrypointTypes<
595 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
596 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
597
598 RestoreLiveRegisters(codegen, locations);
599 __ b(GetExitLabel());
600 }
601
602 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
603
604 private:
605 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
606 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
607 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
608 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
609 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
610 return static_cast<Register>(i);
611 }
612 }
613 // We shall never fail to find a free caller-save register, as
614 // there are more than two core caller-save registers on ARM
615 // (meaning it is possible to find one which is different from
616 // `ref` and `obj`).
617 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
618 LOG(FATAL) << "Could not find a free caller-save register";
619 UNREACHABLE();
620 }
621
Roland Levillain3b359c72015-11-17 19:35:12 +0000622 const Location out_;
623 const Location ref_;
624 const Location obj_;
625 const uint32_t offset_;
626 // An additional location containing an index to an array.
627 // Only used for HArrayGet and the UnsafeGetObject &
628 // UnsafeGetObjectVolatile intrinsics.
629 const Location index_;
630
631 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
632};
633
634// Slow path generating a read barrier for a GC root.
635class ReadBarrierForRootSlowPathARM : public SlowPathCode {
636 public:
637 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000638 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +0000639 DCHECK(kEmitCompilerReadBarrier);
640 }
Roland Levillain3b359c72015-11-17 19:35:12 +0000641
642 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
643 LocationSummary* locations = instruction_->GetLocations();
644 Register reg_out = out_.AsRegister<Register>();
645 DCHECK(locations->CanCall());
646 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +0000647 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
648 << "Unexpected instruction in read barrier for GC root slow path: "
649 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000650
651 __ Bind(GetEntryLabel());
652 SaveLiveRegisters(codegen, locations);
653
654 InvokeRuntimeCallingConvention calling_convention;
655 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
656 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
657 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
658 instruction_,
659 instruction_->GetDexPc(),
660 this);
661 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
662 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
663
664 RestoreLiveRegisters(codegen, locations);
665 __ b(GetExitLabel());
666 }
667
668 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
669
670 private:
Roland Levillain3b359c72015-11-17 19:35:12 +0000671 const Location out_;
672 const Location root_;
673
674 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
675};
676
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000677#undef __
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -0700678// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
679#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
Dave Allison20dfc792014-06-16 20:44:29 -0700680
Aart Bike9f37602015-10-09 11:15:55 -0700681inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700682 switch (cond) {
683 case kCondEQ: return EQ;
684 case kCondNE: return NE;
685 case kCondLT: return LT;
686 case kCondLE: return LE;
687 case kCondGT: return GT;
688 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700689 case kCondB: return LO;
690 case kCondBE: return LS;
691 case kCondA: return HI;
692 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700693 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100694 LOG(FATAL) << "Unreachable";
695 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700696}
697
Aart Bike9f37602015-10-09 11:15:55 -0700698// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100699inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700700 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100701 case kCondEQ: return EQ;
702 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700703 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100704 case kCondLT: return LO;
705 case kCondLE: return LS;
706 case kCondGT: return HI;
707 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700708 // Unsigned remain unchanged.
709 case kCondB: return LO;
710 case kCondBE: return LS;
711 case kCondA: return HI;
712 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700713 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100714 LOG(FATAL) << "Unreachable";
715 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700716}
717
Vladimir Markod6e069b2016-01-18 11:11:01 +0000718inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
719 // The ARM condition codes can express all the necessary branches, see the
720 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
721 // There is no dex instruction or HIR that would need the missing conditions
722 // "equal or unordered" or "not equal".
723 switch (cond) {
724 case kCondEQ: return EQ;
725 case kCondNE: return NE /* unordered */;
726 case kCondLT: return gt_bias ? CC : LT /* unordered */;
727 case kCondLE: return gt_bias ? LS : LE /* unordered */;
728 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
729 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
730 default:
731 LOG(FATAL) << "UNREACHABLE";
732 UNREACHABLE();
733 }
734}
735
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100736void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100737 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100738}
739
740void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100741 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100742}
743
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100744size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
745 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
746 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100747}
748
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100749size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
750 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
751 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100752}
753
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000754size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
755 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
756 return kArmWordSize;
757}
758
759size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
760 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
761 return kArmWordSize;
762}
763
Calin Juravle34166012014-12-19 17:22:29 +0000764CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000765 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100766 const CompilerOptions& compiler_options,
767 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000768 : CodeGenerator(graph,
769 kNumberOfCoreRegisters,
770 kNumberOfSRegisters,
771 kNumberOfRegisterPairs,
772 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
773 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000774 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
775 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100776 compiler_options,
777 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100778 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100779 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100780 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100781 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100782 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +0000783 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000784 uint32_literals_(std::less<uint32_t>(),
785 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko5233f932015-09-29 19:01:15 +0100786 method_patches_(MethodReferenceComparator(),
787 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
788 call_patches_(MethodReferenceComparator(),
789 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000790 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000791 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
792 boot_image_string_patches_(StringReferenceValueComparator(),
793 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
794 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100795 boot_image_type_patches_(TypeReferenceValueComparator(),
796 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
797 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000798 boot_image_address_patches_(std::less<uint32_t>(),
799 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700800 // Always save the LR register to mimic Quick.
801 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100802}
803
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000804void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
805 // Ensure that we fix up branches and literal loads and emit the literal pool.
806 __ FinalizeCode();
807
808 // Adjust native pc offsets in stack maps.
809 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
810 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
811 uint32_t new_position = __ GetAdjustedPosition(old_position);
812 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
813 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100814 // Adjust pc offsets for the disassembly information.
815 if (disasm_info_ != nullptr) {
816 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
817 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
818 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
819 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
820 it.second.start = __ GetAdjustedPosition(it.second.start);
821 it.second.end = __ GetAdjustedPosition(it.second.end);
822 }
823 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
824 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
825 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
826 }
827 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000828
829 CodeGenerator::Finalize(allocator);
830}
831
David Brazdil58282f42016-01-14 12:45:10 +0000832void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100833 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100834 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100835
836 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100837 blocked_core_registers_[SP] = true;
838 blocked_core_registers_[LR] = true;
839 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100840
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100841 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100842 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100843
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100844 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100845 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100846
David Brazdil58282f42016-01-14 12:45:10 +0000847 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100848 // Stubs do not save callee-save floating point registers. If the graph
849 // is debuggable, we need to deal with these registers differently. For
850 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000851 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
852 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
853 }
854 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100855
856 UpdateBlockedPairRegisters();
857}
858
859void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
860 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
861 ArmManagedRegister current =
862 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
863 if (blocked_core_registers_[current.AsRegisterPairLow()]
864 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
865 blocked_register_pairs_[i] = true;
866 }
867 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100868}
869
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100870InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -0800871 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100872 assembler_(codegen->GetAssembler()),
873 codegen_(codegen) {}
874
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000875void CodeGeneratorARM::ComputeSpillMask() {
876 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
877 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +0000878 // There is no easy instruction to restore just the PC on thumb2. We spill and
879 // restore another arbitrary register.
880 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000881 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
882 // We use vpush and vpop for saving and restoring floating point registers, which take
883 // a SRegister and the number of registers to save/restore after that SRegister. We
884 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
885 // but in the range.
886 if (fpu_spill_mask_ != 0) {
887 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
888 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
889 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
890 fpu_spill_mask_ |= (1 << i);
891 }
892 }
893}
894
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100895static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100896 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100897}
898
899static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100900 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100901}
902
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000903void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000904 bool skip_overflow_check =
905 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000906 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000907 __ Bind(&frame_entry_label_);
908
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000909 if (HasEmptyFrame()) {
910 return;
911 }
912
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100913 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000914 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
915 __ LoadFromOffset(kLoadWord, IP, IP, 0);
916 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100917 }
918
Andreas Gampe501fd632015-09-10 16:11:06 -0700919 __ PushList(core_spill_mask_);
920 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
921 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000922 if (fpu_spill_mask_ != 0) {
923 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
924 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100925 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100926 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000927 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100928 int adjust = GetFrameSize() - FrameEntrySpillSize();
929 __ AddConstant(SP, -adjust);
930 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100931 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000932}
933
934void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000935 if (HasEmptyFrame()) {
936 __ bx(LR);
937 return;
938 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100939 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100940 int adjust = GetFrameSize() - FrameEntrySpillSize();
941 __ AddConstant(SP, adjust);
942 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000943 if (fpu_spill_mask_ != 0) {
944 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
945 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100946 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
947 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000948 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700949 // Pop LR into PC to return.
950 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
951 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
952 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100953 __ cfi().RestoreState();
954 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000955}
956
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100957void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700958 Label* label = GetLabelOf(block);
959 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000960}
961
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100962Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100963 switch (type) {
964 case Primitive::kPrimBoolean:
965 case Primitive::kPrimByte:
966 case Primitive::kPrimChar:
967 case Primitive::kPrimShort:
968 case Primitive::kPrimInt:
969 case Primitive::kPrimNot: {
970 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000971 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100972 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100973 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100974 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000975 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100976 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100977 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100978
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000979 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100980 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000981 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100982 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000983 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100984 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000985 if (calling_convention.GetRegisterAt(index) == R1) {
986 // Skip R1, and use R2_R3 instead.
987 gp_index_++;
988 index++;
989 }
990 }
991 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
992 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000993 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100994
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000995 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000996 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100997 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000998 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
999 }
1000 }
1001
1002 case Primitive::kPrimFloat: {
1003 uint32_t stack_index = stack_index_++;
1004 if (float_index_ % 2 == 0) {
1005 float_index_ = std::max(double_index_, float_index_);
1006 }
1007 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1008 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1009 } else {
1010 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1011 }
1012 }
1013
1014 case Primitive::kPrimDouble: {
1015 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1016 uint32_t stack_index = stack_index_;
1017 stack_index_ += 2;
1018 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1019 uint32_t index = double_index_;
1020 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001021 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001022 calling_convention.GetFpuRegisterAt(index),
1023 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001024 DCHECK(ExpectedPairLayout(result));
1025 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001026 } else {
1027 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001028 }
1029 }
1030
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001031 case Primitive::kPrimVoid:
1032 LOG(FATAL) << "Unexpected parameter type " << type;
1033 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001034 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001035 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001036}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001037
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001038Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001039 switch (type) {
1040 case Primitive::kPrimBoolean:
1041 case Primitive::kPrimByte:
1042 case Primitive::kPrimChar:
1043 case Primitive::kPrimShort:
1044 case Primitive::kPrimInt:
1045 case Primitive::kPrimNot: {
1046 return Location::RegisterLocation(R0);
1047 }
1048
1049 case Primitive::kPrimFloat: {
1050 return Location::FpuRegisterLocation(S0);
1051 }
1052
1053 case Primitive::kPrimLong: {
1054 return Location::RegisterPairLocation(R0, R1);
1055 }
1056
1057 case Primitive::kPrimDouble: {
1058 return Location::FpuRegisterPairLocation(S0, S1);
1059 }
1060
1061 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001062 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001063 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001064
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001065 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001066}
1067
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001068Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1069 return Location::RegisterLocation(kMethodRegisterArgument);
1070}
1071
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001072void CodeGeneratorARM::Move32(Location destination, Location source) {
1073 if (source.Equals(destination)) {
1074 return;
1075 }
1076 if (destination.IsRegister()) {
1077 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001078 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001079 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001080 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001081 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001082 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001083 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001084 } else if (destination.IsFpuRegister()) {
1085 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001086 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001087 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001088 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001089 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001090 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001091 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001092 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001093 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001094 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001095 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001097 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001098 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001099 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001100 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1101 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001102 }
1103 }
1104}
1105
1106void CodeGeneratorARM::Move64(Location destination, Location source) {
1107 if (source.Equals(destination)) {
1108 return;
1109 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001110 if (destination.IsRegisterPair()) {
1111 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001112 EmitParallelMoves(
1113 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1114 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001115 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001116 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001117 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1118 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001119 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001120 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001121 } else if (source.IsFpuRegisterPair()) {
1122 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1123 destination.AsRegisterPairHigh<Register>(),
1124 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001125 } else {
1126 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001127 DCHECK(ExpectedPairLayout(destination));
1128 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1129 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001130 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001131 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001132 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001133 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1134 SP,
1135 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001136 } else if (source.IsRegisterPair()) {
1137 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1138 source.AsRegisterPairLow<Register>(),
1139 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001140 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001141 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001142 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001143 } else {
1144 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001145 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001146 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001147 if (source.AsRegisterPairLow<Register>() == R1) {
1148 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001149 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1150 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001151 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001152 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001153 SP, destination.GetStackIndex());
1154 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001155 } else if (source.IsFpuRegisterPair()) {
1156 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1157 SP,
1158 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001159 } else {
1160 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001161 EmitParallelMoves(
1162 Location::StackSlot(source.GetStackIndex()),
1163 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001164 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001165 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001166 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1167 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001168 }
1169 }
1170}
1171
Calin Juravle175dc732015-08-25 15:42:32 +01001172void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1173 DCHECK(location.IsRegister());
1174 __ LoadImmediate(location.AsRegister<Register>(), value);
1175}
1176
Calin Juravlee460d1d2015-09-29 04:52:17 +01001177void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001178 HParallelMove move(GetGraph()->GetArena());
1179 move.AddMove(src, dst, dst_type, nullptr);
1180 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001181}
1182
1183void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1184 if (location.IsRegister()) {
1185 locations->AddTemp(location);
1186 } else if (location.IsRegisterPair()) {
1187 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1188 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1189 } else {
1190 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1191 }
1192}
1193
Calin Juravle175dc732015-08-25 15:42:32 +01001194void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1195 HInstruction* instruction,
1196 uint32_t dex_pc,
1197 SlowPathCode* slow_path) {
1198 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1199 instruction,
1200 dex_pc,
1201 slow_path);
1202}
1203
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001204void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1205 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001206 uint32_t dex_pc,
1207 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001208 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001209 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1210 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001211 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001212}
1213
David Brazdilfc6a86a2015-06-26 10:33:45 +00001214void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001215 DCHECK(!successor->IsExitBlock());
1216
1217 HBasicBlock* block = got->GetBlock();
1218 HInstruction* previous = got->GetPrevious();
1219
1220 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001221 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001222 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1223 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1224 return;
1225 }
1226
1227 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1228 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1229 }
1230 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001231 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001232 }
1233}
1234
David Brazdilfc6a86a2015-06-26 10:33:45 +00001235void LocationsBuilderARM::VisitGoto(HGoto* got) {
1236 got->SetLocations(nullptr);
1237}
1238
1239void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1240 HandleGoto(got, got->GetSuccessor());
1241}
1242
1243void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1244 try_boundary->SetLocations(nullptr);
1245}
1246
1247void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1248 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1249 if (!successor->IsExitBlock()) {
1250 HandleGoto(try_boundary, successor);
1251 }
1252}
1253
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001254void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001255 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001256}
1257
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001258void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001259}
1260
Roland Levillain4fa13f62015-07-06 18:11:54 +01001261void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1262 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001263 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001264 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001265 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001266}
1267
1268void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1269 Label* true_label,
1270 Label* false_label) {
1271 LocationSummary* locations = cond->GetLocations();
1272 Location left = locations->InAt(0);
1273 Location right = locations->InAt(1);
1274 IfCondition if_cond = cond->GetCondition();
1275
1276 Register left_high = left.AsRegisterPairHigh<Register>();
1277 Register left_low = left.AsRegisterPairLow<Register>();
1278 IfCondition true_high_cond = if_cond;
1279 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001280 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001281
1282 // Set the conditions for the test, remembering that == needs to be
1283 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001284 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001285 switch (if_cond) {
1286 case kCondEQ:
1287 case kCondNE:
1288 // Nothing to do.
1289 break;
1290 case kCondLT:
1291 false_high_cond = kCondGT;
1292 break;
1293 case kCondLE:
1294 true_high_cond = kCondLT;
1295 break;
1296 case kCondGT:
1297 false_high_cond = kCondLT;
1298 break;
1299 case kCondGE:
1300 true_high_cond = kCondGT;
1301 break;
Aart Bike9f37602015-10-09 11:15:55 -07001302 case kCondB:
1303 false_high_cond = kCondA;
1304 break;
1305 case kCondBE:
1306 true_high_cond = kCondB;
1307 break;
1308 case kCondA:
1309 false_high_cond = kCondB;
1310 break;
1311 case kCondAE:
1312 true_high_cond = kCondA;
1313 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001314 }
1315 if (right.IsConstant()) {
1316 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1317 int32_t val_low = Low32Bits(value);
1318 int32_t val_high = High32Bits(value);
1319
Vladimir Markoac6ac102015-12-17 12:14:00 +00001320 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001321 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001322 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001323 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001324 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001325 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001326 __ b(true_label, ARMCondition(true_high_cond));
1327 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001328 }
1329 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001330 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001331 } else {
1332 Register right_high = right.AsRegisterPairHigh<Register>();
1333 Register right_low = right.AsRegisterPairLow<Register>();
1334
1335 __ cmp(left_high, ShifterOperand(right_high));
1336 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001337 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001338 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001339 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001340 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001341 __ b(true_label, ARMCondition(true_high_cond));
1342 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001343 }
1344 // Must be equal high, so compare the lows.
1345 __ cmp(left_low, ShifterOperand(right_low));
1346 }
1347 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001348 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001349 __ b(true_label, final_condition);
1350}
1351
David Brazdil0debae72015-11-12 18:37:00 +00001352void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1353 Label* true_target_in,
1354 Label* false_target_in) {
1355 // Generated branching requires both targets to be explicit. If either of the
1356 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1357 Label fallthrough_target;
1358 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1359 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1360
Roland Levillain4fa13f62015-07-06 18:11:54 +01001361 LocationSummary* locations = condition->GetLocations();
1362 Location left = locations->InAt(0);
1363 Location right = locations->InAt(1);
1364
Roland Levillain4fa13f62015-07-06 18:11:54 +01001365 Primitive::Type type = condition->InputAt(0)->GetType();
1366 switch (type) {
1367 case Primitive::kPrimLong:
1368 GenerateLongComparesAndJumps(condition, true_target, false_target);
1369 break;
1370 case Primitive::kPrimFloat:
1371 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1372 GenerateFPJumps(condition, true_target, false_target);
1373 break;
1374 case Primitive::kPrimDouble:
1375 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1376 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1377 GenerateFPJumps(condition, true_target, false_target);
1378 break;
1379 default:
1380 LOG(FATAL) << "Unexpected compare type " << type;
1381 }
1382
David Brazdil0debae72015-11-12 18:37:00 +00001383 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001384 __ b(false_target);
1385 }
David Brazdil0debae72015-11-12 18:37:00 +00001386
1387 if (fallthrough_target.IsLinked()) {
1388 __ Bind(&fallthrough_target);
1389 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001390}
1391
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001392void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001393 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001394 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001395 Label* false_target) {
1396 HInstruction* cond = instruction->InputAt(condition_input_index);
1397
1398 if (true_target == nullptr && false_target == nullptr) {
1399 // Nothing to do. The code always falls through.
1400 return;
1401 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001402 // Constant condition, statically compared against "true" (integer value 1).
1403 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001404 if (true_target != nullptr) {
1405 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001406 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001407 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001408 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001409 if (false_target != nullptr) {
1410 __ b(false_target);
1411 }
1412 }
1413 return;
1414 }
1415
1416 // The following code generates these patterns:
1417 // (1) true_target == nullptr && false_target != nullptr
1418 // - opposite condition true => branch to false_target
1419 // (2) true_target != nullptr && false_target == nullptr
1420 // - condition true => branch to true_target
1421 // (3) true_target != nullptr && false_target != nullptr
1422 // - condition true => branch to true_target
1423 // - branch to false_target
1424 if (IsBooleanValueOrMaterializedCondition(cond)) {
1425 // Condition has been materialized, compare the output to 0.
1426 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1427 DCHECK(cond_val.IsRegister());
1428 if (true_target == nullptr) {
1429 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1430 } else {
1431 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001432 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001433 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001434 // Condition has not been materialized. Use its inputs as the comparison and
1435 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001436 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001437
1438 // If this is a long or FP comparison that has been folded into
1439 // the HCondition, generate the comparison directly.
1440 Primitive::Type type = condition->InputAt(0)->GetType();
1441 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1442 GenerateCompareTestAndBranch(condition, true_target, false_target);
1443 return;
1444 }
1445
1446 LocationSummary* locations = cond->GetLocations();
1447 DCHECK(locations->InAt(0).IsRegister());
1448 Register left = locations->InAt(0).AsRegister<Register>();
1449 Location right = locations->InAt(1);
1450 if (right.IsRegister()) {
1451 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001452 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001453 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001454 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001455 }
1456 if (true_target == nullptr) {
1457 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1458 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001459 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001460 }
Dave Allison20dfc792014-06-16 20:44:29 -07001461 }
David Brazdil0debae72015-11-12 18:37:00 +00001462
1463 // If neither branch falls through (case 3), the conditional branch to `true_target`
1464 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1465 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001466 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001467 }
1468}
1469
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001470void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001471 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1472 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001473 locations->SetInAt(0, Location::RequiresRegister());
1474 }
1475}
1476
1477void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001478 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1479 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1480 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1481 nullptr : codegen_->GetLabelOf(true_successor);
1482 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1483 nullptr : codegen_->GetLabelOf(false_successor);
1484 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001485}
1486
1487void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1488 LocationSummary* locations = new (GetGraph()->GetArena())
1489 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001490 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001491 locations->SetInAt(0, Location::RequiresRegister());
1492 }
1493}
1494
1495void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001496 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001497 GenerateTestAndBranch(deoptimize,
1498 /* condition_input_index */ 0,
1499 slow_path->GetEntryLabel(),
1500 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001501}
Dave Allison20dfc792014-06-16 20:44:29 -07001502
David Brazdil74eb1b22015-12-14 11:44:01 +00001503void LocationsBuilderARM::VisitSelect(HSelect* select) {
1504 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1505 if (Primitive::IsFloatingPointType(select->GetType())) {
1506 locations->SetInAt(0, Location::RequiresFpuRegister());
1507 locations->SetInAt(1, Location::RequiresFpuRegister());
1508 } else {
1509 locations->SetInAt(0, Location::RequiresRegister());
1510 locations->SetInAt(1, Location::RequiresRegister());
1511 }
1512 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1513 locations->SetInAt(2, Location::RequiresRegister());
1514 }
1515 locations->SetOut(Location::SameAsFirstInput());
1516}
1517
1518void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1519 LocationSummary* locations = select->GetLocations();
1520 Label false_target;
1521 GenerateTestAndBranch(select,
1522 /* condition_input_index */ 2,
1523 /* true_target */ nullptr,
1524 &false_target);
1525 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1526 __ Bind(&false_target);
1527}
1528
David Srbecky0cf44932015-12-09 14:09:59 +00001529void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1530 new (GetGraph()->GetArena()) LocationSummary(info);
1531}
1532
David Srbeckyd28f4a02016-03-14 17:14:24 +00001533void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
1534 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001535}
1536
1537void CodeGeneratorARM::GenerateNop() {
1538 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001539}
1540
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001541void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001542 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001543 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001544 // Handle the long/FP comparisons made in instruction simplification.
1545 switch (cond->InputAt(0)->GetType()) {
1546 case Primitive::kPrimLong:
1547 locations->SetInAt(0, Location::RequiresRegister());
1548 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001549 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001550 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1551 }
1552 break;
1553
1554 case Primitive::kPrimFloat:
1555 case Primitive::kPrimDouble:
1556 locations->SetInAt(0, Location::RequiresFpuRegister());
1557 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00001558 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001559 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1560 }
1561 break;
1562
1563 default:
1564 locations->SetInAt(0, Location::RequiresRegister());
1565 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001566 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001567 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1568 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001569 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001570}
1571
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001572void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001573 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001574 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001575 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001576
1577 LocationSummary* locations = cond->GetLocations();
1578 Location left = locations->InAt(0);
1579 Location right = locations->InAt(1);
1580 Register out = locations->Out().AsRegister<Register>();
1581 Label true_label, false_label;
1582
1583 switch (cond->InputAt(0)->GetType()) {
1584 default: {
1585 // Integer case.
1586 if (right.IsRegister()) {
1587 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1588 } else {
1589 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001590 __ CmpConstant(left.AsRegister<Register>(),
1591 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001592 }
Aart Bike9f37602015-10-09 11:15:55 -07001593 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001594 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001595 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001596 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001597 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001598 return;
1599 }
1600 case Primitive::kPrimLong:
1601 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1602 break;
1603 case Primitive::kPrimFloat:
1604 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1605 GenerateFPJumps(cond, &true_label, &false_label);
1606 break;
1607 case Primitive::kPrimDouble:
1608 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1609 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1610 GenerateFPJumps(cond, &true_label, &false_label);
1611 break;
1612 }
1613
1614 // Convert the jumps into the result.
1615 Label done_label;
1616
1617 // False case: result = 0.
1618 __ Bind(&false_label);
1619 __ LoadImmediate(out, 0);
1620 __ b(&done_label);
1621
1622 // True case: result = 1.
1623 __ Bind(&true_label);
1624 __ LoadImmediate(out, 1);
1625 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001626}
1627
1628void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001629 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001630}
1631
1632void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001633 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001634}
1635
1636void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001637 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001638}
1639
1640void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001641 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001642}
1643
1644void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001645 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001646}
1647
1648void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001649 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001650}
1651
1652void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001653 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001654}
1655
1656void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001657 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001658}
1659
1660void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001661 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001662}
1663
1664void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001665 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001666}
1667
1668void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001669 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001670}
1671
1672void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001673 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001674}
1675
Aart Bike9f37602015-10-09 11:15:55 -07001676void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001677 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001678}
1679
1680void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001681 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001682}
1683
1684void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001685 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001686}
1687
1688void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001689 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001690}
1691
1692void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001693 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001694}
1695
1696void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001697 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001698}
1699
1700void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001701 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001702}
1703
1704void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001705 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001706}
1707
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001708void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001709 LocationSummary* locations =
1710 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001711 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001712}
1713
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001714void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001715 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001716}
1717
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001718void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1719 LocationSummary* locations =
1720 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1721 locations->SetOut(Location::ConstantLocation(constant));
1722}
1723
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001724void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001725 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001726}
1727
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001728void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001729 LocationSummary* locations =
1730 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001731 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001732}
1733
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001734void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001735 // Will be generated at use site.
1736}
1737
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001738void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1739 LocationSummary* locations =
1740 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1741 locations->SetOut(Location::ConstantLocation(constant));
1742}
1743
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001744void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001745 // Will be generated at use site.
1746}
1747
1748void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1749 LocationSummary* locations =
1750 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1751 locations->SetOut(Location::ConstantLocation(constant));
1752}
1753
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001754void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001755 // Will be generated at use site.
1756}
1757
Calin Juravle27df7582015-04-17 19:12:31 +01001758void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1759 memory_barrier->SetLocations(nullptr);
1760}
1761
1762void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00001763 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01001764}
1765
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001766void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001767 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001768}
1769
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001770void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001771 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001772}
1773
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001774void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001775 LocationSummary* locations =
1776 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001777 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001778}
1779
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001780void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001781 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001782}
1783
Calin Juravle175dc732015-08-25 15:42:32 +01001784void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1785 // The trampoline uses the same calling convention as dex calling conventions,
1786 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1787 // the method_idx.
1788 HandleInvoke(invoke);
1789}
1790
1791void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1792 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1793}
1794
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001795void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001796 // Explicit clinit checks triggered by static invokes must have been pruned by
1797 // art::PrepareForRegisterAllocation.
1798 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001799
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001800 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001801 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001802 codegen_->GetInstructionSetFeatures());
1803 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001804 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1805 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1806 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001807 return;
1808 }
1809
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001810 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001811
1812 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1813 if (invoke->HasPcRelativeDexCache()) {
1814 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1815 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001816}
1817
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001818static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1819 if (invoke->GetLocations()->Intrinsified()) {
1820 IntrinsicCodeGeneratorARM intrinsic(codegen);
1821 intrinsic.Dispatch(invoke);
1822 return true;
1823 }
1824 return false;
1825}
1826
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001827void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001828 // Explicit clinit checks triggered by static invokes must have been pruned by
1829 // art::PrepareForRegisterAllocation.
1830 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001831
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001832 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1833 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001834 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001835
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001836 LocationSummary* locations = invoke->GetLocations();
1837 codegen_->GenerateStaticOrDirectCall(
1838 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001839 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001840}
1841
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001842void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001843 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001844 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001845}
1846
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001847void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001848 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001849 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001850 codegen_->GetInstructionSetFeatures());
1851 if (intrinsic.TryDispatch(invoke)) {
1852 return;
1853 }
1854
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001855 HandleInvoke(invoke);
1856}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001857
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001858void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001859 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1860 return;
1861 }
1862
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001863 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001864 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001865 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001866}
1867
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001868void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1869 HandleInvoke(invoke);
1870 // Add the hidden argument.
1871 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1872}
1873
1874void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1875 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001876 LocationSummary* locations = invoke->GetLocations();
1877 Register temp = locations->GetTemp(0).AsRegister<Register>();
1878 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001879 Location receiver = locations->InAt(0);
1880 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1881
Roland Levillain3b359c72015-11-17 19:35:12 +00001882 // Set the hidden argument. This is safe to do this here, as R12
1883 // won't be modified thereafter, before the `blx` (call) instruction.
1884 DCHECK_EQ(R12, hidden_reg);
1885 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001886
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001887 if (receiver.IsStackSlot()) {
1888 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00001889 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001890 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1891 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00001892 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00001893 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001894 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001895 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00001896 // Instead of simply (possibly) unpoisoning `temp` here, we should
1897 // emit a read barrier for the previous class reference load.
1898 // However this is not required in practice, as this is an
1899 // intermediate/temporary reference and because the current
1900 // concurrent copying collector keeps the from-space memory
1901 // intact/accessible until the end of the marking phase (the
1902 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01001903 __ MaybeUnpoisonHeapReference(temp);
Nelli Kimbadee982016-05-13 13:08:53 +03001904 __ LoadFromOffset(kLoadWord, temp, temp,
1905 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
1906 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity50706432016-06-14 11:31:04 -07001907 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001908 // temp = temp->GetImtEntryAt(method_offset);
Nelli Kimbadee982016-05-13 13:08:53 +03001909 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001910 uint32_t entry_point =
1911 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001912 // LR = temp->GetEntryPoint();
1913 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1914 // LR();
1915 __ blx(LR);
1916 DCHECK(!codegen_->IsLeafMethod());
1917 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1918}
1919
Roland Levillain88cb1752014-10-20 16:36:47 +01001920void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1921 LocationSummary* locations =
1922 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1923 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001924 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001925 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001926 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1927 break;
1928 }
1929 case Primitive::kPrimLong: {
1930 locations->SetInAt(0, Location::RequiresRegister());
1931 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001932 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001933 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001934
Roland Levillain88cb1752014-10-20 16:36:47 +01001935 case Primitive::kPrimFloat:
1936 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001937 locations->SetInAt(0, Location::RequiresFpuRegister());
1938 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001939 break;
1940
1941 default:
1942 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1943 }
1944}
1945
1946void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1947 LocationSummary* locations = neg->GetLocations();
1948 Location out = locations->Out();
1949 Location in = locations->InAt(0);
1950 switch (neg->GetResultType()) {
1951 case Primitive::kPrimInt:
1952 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001953 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001954 break;
1955
1956 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001957 DCHECK(in.IsRegisterPair());
1958 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1959 __ rsbs(out.AsRegisterPairLow<Register>(),
1960 in.AsRegisterPairLow<Register>(),
1961 ShifterOperand(0));
1962 // We cannot emit an RSC (Reverse Subtract with Carry)
1963 // instruction here, as it does not exist in the Thumb-2
1964 // instruction set. We use the following approach
1965 // using SBC and SUB instead.
1966 //
1967 // out.hi = -C
1968 __ sbc(out.AsRegisterPairHigh<Register>(),
1969 out.AsRegisterPairHigh<Register>(),
1970 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1971 // out.hi = out.hi - in.hi
1972 __ sub(out.AsRegisterPairHigh<Register>(),
1973 out.AsRegisterPairHigh<Register>(),
1974 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1975 break;
1976
Roland Levillain88cb1752014-10-20 16:36:47 +01001977 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001978 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001979 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001980 break;
1981
Roland Levillain88cb1752014-10-20 16:36:47 +01001982 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001983 DCHECK(in.IsFpuRegisterPair());
1984 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1985 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001986 break;
1987
1988 default:
1989 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1990 }
1991}
1992
Roland Levillaindff1f282014-11-05 14:15:05 +00001993void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001994 Primitive::Type result_type = conversion->GetResultType();
1995 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001996 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001997
Roland Levillain5b3ee562015-04-14 16:02:41 +01001998 // The float-to-long, double-to-long and long-to-float type conversions
1999 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002000 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002001 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2002 && result_type == Primitive::kPrimLong)
2003 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002004 ? LocationSummary::kCall
2005 : LocationSummary::kNoCall;
2006 LocationSummary* locations =
2007 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2008
David Brazdilb2bd1c52015-03-25 11:17:37 +00002009 // The Java language does not allow treating boolean as an integral type but
2010 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002011
Roland Levillaindff1f282014-11-05 14:15:05 +00002012 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002013 case Primitive::kPrimByte:
2014 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002015 case Primitive::kPrimLong:
2016 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002017 case Primitive::kPrimBoolean:
2018 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002019 case Primitive::kPrimShort:
2020 case Primitive::kPrimInt:
2021 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002022 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002023 locations->SetInAt(0, Location::RequiresRegister());
2024 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2025 break;
2026
2027 default:
2028 LOG(FATAL) << "Unexpected type conversion from " << input_type
2029 << " to " << result_type;
2030 }
2031 break;
2032
Roland Levillain01a8d712014-11-14 16:27:39 +00002033 case Primitive::kPrimShort:
2034 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002035 case Primitive::kPrimLong:
2036 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002037 case Primitive::kPrimBoolean:
2038 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002039 case Primitive::kPrimByte:
2040 case Primitive::kPrimInt:
2041 case Primitive::kPrimChar:
2042 // Processing a Dex `int-to-short' instruction.
2043 locations->SetInAt(0, Location::RequiresRegister());
2044 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2045 break;
2046
2047 default:
2048 LOG(FATAL) << "Unexpected type conversion from " << input_type
2049 << " to " << result_type;
2050 }
2051 break;
2052
Roland Levillain946e1432014-11-11 17:35:19 +00002053 case Primitive::kPrimInt:
2054 switch (input_type) {
2055 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002056 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002057 locations->SetInAt(0, Location::Any());
2058 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2059 break;
2060
2061 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002062 // Processing a Dex `float-to-int' instruction.
2063 locations->SetInAt(0, Location::RequiresFpuRegister());
2064 locations->SetOut(Location::RequiresRegister());
2065 locations->AddTemp(Location::RequiresFpuRegister());
2066 break;
2067
Roland Levillain946e1432014-11-11 17:35:19 +00002068 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002069 // Processing a Dex `double-to-int' instruction.
2070 locations->SetInAt(0, Location::RequiresFpuRegister());
2071 locations->SetOut(Location::RequiresRegister());
2072 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002073 break;
2074
2075 default:
2076 LOG(FATAL) << "Unexpected type conversion from " << input_type
2077 << " to " << result_type;
2078 }
2079 break;
2080
Roland Levillaindff1f282014-11-05 14:15:05 +00002081 case Primitive::kPrimLong:
2082 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002083 case Primitive::kPrimBoolean:
2084 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002085 case Primitive::kPrimByte:
2086 case Primitive::kPrimShort:
2087 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002088 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002089 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002090 locations->SetInAt(0, Location::RequiresRegister());
2091 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2092 break;
2093
Roland Levillain624279f2014-12-04 11:54:28 +00002094 case Primitive::kPrimFloat: {
2095 // Processing a Dex `float-to-long' instruction.
2096 InvokeRuntimeCallingConvention calling_convention;
2097 locations->SetInAt(0, Location::FpuRegisterLocation(
2098 calling_convention.GetFpuRegisterAt(0)));
2099 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2100 break;
2101 }
2102
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002103 case Primitive::kPrimDouble: {
2104 // Processing a Dex `double-to-long' instruction.
2105 InvokeRuntimeCallingConvention calling_convention;
2106 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2107 calling_convention.GetFpuRegisterAt(0),
2108 calling_convention.GetFpuRegisterAt(1)));
2109 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002110 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002111 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002112
2113 default:
2114 LOG(FATAL) << "Unexpected type conversion from " << input_type
2115 << " to " << result_type;
2116 }
2117 break;
2118
Roland Levillain981e4542014-11-14 11:47:14 +00002119 case Primitive::kPrimChar:
2120 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002121 case Primitive::kPrimLong:
2122 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002123 case Primitive::kPrimBoolean:
2124 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002125 case Primitive::kPrimByte:
2126 case Primitive::kPrimShort:
2127 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002128 // Processing a Dex `int-to-char' instruction.
2129 locations->SetInAt(0, Location::RequiresRegister());
2130 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2131 break;
2132
2133 default:
2134 LOG(FATAL) << "Unexpected type conversion from " << input_type
2135 << " to " << result_type;
2136 }
2137 break;
2138
Roland Levillaindff1f282014-11-05 14:15:05 +00002139 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002140 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002141 case Primitive::kPrimBoolean:
2142 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002143 case Primitive::kPrimByte:
2144 case Primitive::kPrimShort:
2145 case Primitive::kPrimInt:
2146 case Primitive::kPrimChar:
2147 // Processing a Dex `int-to-float' instruction.
2148 locations->SetInAt(0, Location::RequiresRegister());
2149 locations->SetOut(Location::RequiresFpuRegister());
2150 break;
2151
Roland Levillain5b3ee562015-04-14 16:02:41 +01002152 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002153 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002154 InvokeRuntimeCallingConvention calling_convention;
2155 locations->SetInAt(0, Location::RegisterPairLocation(
2156 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2157 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002158 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002159 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002160
Roland Levillaincff13742014-11-17 14:32:17 +00002161 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002162 // Processing a Dex `double-to-float' instruction.
2163 locations->SetInAt(0, Location::RequiresFpuRegister());
2164 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002165 break;
2166
2167 default:
2168 LOG(FATAL) << "Unexpected type conversion from " << input_type
2169 << " to " << result_type;
2170 };
2171 break;
2172
Roland Levillaindff1f282014-11-05 14:15:05 +00002173 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002174 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002175 case Primitive::kPrimBoolean:
2176 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002177 case Primitive::kPrimByte:
2178 case Primitive::kPrimShort:
2179 case Primitive::kPrimInt:
2180 case Primitive::kPrimChar:
2181 // Processing a Dex `int-to-double' instruction.
2182 locations->SetInAt(0, Location::RequiresRegister());
2183 locations->SetOut(Location::RequiresFpuRegister());
2184 break;
2185
2186 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002187 // Processing a Dex `long-to-double' instruction.
2188 locations->SetInAt(0, Location::RequiresRegister());
2189 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002190 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002191 locations->AddTemp(Location::RequiresFpuRegister());
2192 break;
2193
Roland Levillaincff13742014-11-17 14:32:17 +00002194 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002195 // Processing a Dex `float-to-double' instruction.
2196 locations->SetInAt(0, Location::RequiresFpuRegister());
2197 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002198 break;
2199
2200 default:
2201 LOG(FATAL) << "Unexpected type conversion from " << input_type
2202 << " to " << result_type;
2203 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002204 break;
2205
2206 default:
2207 LOG(FATAL) << "Unexpected type conversion from " << input_type
2208 << " to " << result_type;
2209 }
2210}
2211
2212void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2213 LocationSummary* locations = conversion->GetLocations();
2214 Location out = locations->Out();
2215 Location in = locations->InAt(0);
2216 Primitive::Type result_type = conversion->GetResultType();
2217 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002218 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002219 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002220 case Primitive::kPrimByte:
2221 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002222 case Primitive::kPrimLong:
2223 // Type conversion from long to byte is a result of code transformations.
2224 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2225 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002226 case Primitive::kPrimBoolean:
2227 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002228 case Primitive::kPrimShort:
2229 case Primitive::kPrimInt:
2230 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002231 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002232 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002233 break;
2234
2235 default:
2236 LOG(FATAL) << "Unexpected type conversion from " << input_type
2237 << " to " << result_type;
2238 }
2239 break;
2240
Roland Levillain01a8d712014-11-14 16:27:39 +00002241 case Primitive::kPrimShort:
2242 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002243 case Primitive::kPrimLong:
2244 // Type conversion from long to short is a result of code transformations.
2245 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2246 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002247 case Primitive::kPrimBoolean:
2248 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002249 case Primitive::kPrimByte:
2250 case Primitive::kPrimInt:
2251 case Primitive::kPrimChar:
2252 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002253 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002254 break;
2255
2256 default:
2257 LOG(FATAL) << "Unexpected type conversion from " << input_type
2258 << " to " << result_type;
2259 }
2260 break;
2261
Roland Levillain946e1432014-11-11 17:35:19 +00002262 case Primitive::kPrimInt:
2263 switch (input_type) {
2264 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002265 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002266 DCHECK(out.IsRegister());
2267 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002268 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002269 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002270 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002271 } else {
2272 DCHECK(in.IsConstant());
2273 DCHECK(in.GetConstant()->IsLongConstant());
2274 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002275 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002276 }
2277 break;
2278
Roland Levillain3f8f9362014-12-02 17:45:01 +00002279 case Primitive::kPrimFloat: {
2280 // Processing a Dex `float-to-int' instruction.
2281 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2282 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2283 __ vcvtis(temp, temp);
2284 __ vmovrs(out.AsRegister<Register>(), temp);
2285 break;
2286 }
2287
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002288 case Primitive::kPrimDouble: {
2289 // Processing a Dex `double-to-int' instruction.
2290 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2291 DRegister temp_d = FromLowSToD(temp_s);
2292 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2293 __ vcvtid(temp_s, temp_d);
2294 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002295 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002296 }
Roland Levillain946e1432014-11-11 17:35:19 +00002297
2298 default:
2299 LOG(FATAL) << "Unexpected type conversion from " << input_type
2300 << " to " << result_type;
2301 }
2302 break;
2303
Roland Levillaindff1f282014-11-05 14:15:05 +00002304 case Primitive::kPrimLong:
2305 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002306 case Primitive::kPrimBoolean:
2307 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002308 case Primitive::kPrimByte:
2309 case Primitive::kPrimShort:
2310 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002311 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002312 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002313 DCHECK(out.IsRegisterPair());
2314 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002315 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002316 // Sign extension.
2317 __ Asr(out.AsRegisterPairHigh<Register>(),
2318 out.AsRegisterPairLow<Register>(),
2319 31);
2320 break;
2321
2322 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002323 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002324 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2325 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002326 conversion->GetDexPc(),
2327 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002328 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002329 break;
2330
Roland Levillaindff1f282014-11-05 14:15:05 +00002331 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002332 // Processing a Dex `double-to-long' instruction.
2333 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2334 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002335 conversion->GetDexPc(),
2336 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002337 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002338 break;
2339
2340 default:
2341 LOG(FATAL) << "Unexpected type conversion from " << input_type
2342 << " to " << result_type;
2343 }
2344 break;
2345
Roland Levillain981e4542014-11-14 11:47:14 +00002346 case Primitive::kPrimChar:
2347 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002348 case Primitive::kPrimLong:
2349 // Type conversion from long to char is a result of code transformations.
2350 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2351 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002352 case Primitive::kPrimBoolean:
2353 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002354 case Primitive::kPrimByte:
2355 case Primitive::kPrimShort:
2356 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002357 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002358 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002359 break;
2360
2361 default:
2362 LOG(FATAL) << "Unexpected type conversion from " << input_type
2363 << " to " << result_type;
2364 }
2365 break;
2366
Roland Levillaindff1f282014-11-05 14:15:05 +00002367 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002368 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002369 case Primitive::kPrimBoolean:
2370 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002371 case Primitive::kPrimByte:
2372 case Primitive::kPrimShort:
2373 case Primitive::kPrimInt:
2374 case Primitive::kPrimChar: {
2375 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002376 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2377 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002378 break;
2379 }
2380
Roland Levillain5b3ee562015-04-14 16:02:41 +01002381 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002382 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002383 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2384 conversion,
2385 conversion->GetDexPc(),
2386 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002387 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002388 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002389
Roland Levillaincff13742014-11-17 14:32:17 +00002390 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002391 // Processing a Dex `double-to-float' instruction.
2392 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2393 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002394 break;
2395
2396 default:
2397 LOG(FATAL) << "Unexpected type conversion from " << input_type
2398 << " to " << result_type;
2399 };
2400 break;
2401
Roland Levillaindff1f282014-11-05 14:15:05 +00002402 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002403 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002404 case Primitive::kPrimBoolean:
2405 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002406 case Primitive::kPrimByte:
2407 case Primitive::kPrimShort:
2408 case Primitive::kPrimInt:
2409 case Primitive::kPrimChar: {
2410 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002411 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002412 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2413 out.AsFpuRegisterPairLow<SRegister>());
2414 break;
2415 }
2416
Roland Levillain647b9ed2014-11-27 12:06:00 +00002417 case Primitive::kPrimLong: {
2418 // Processing a Dex `long-to-double' instruction.
2419 Register low = in.AsRegisterPairLow<Register>();
2420 Register high = in.AsRegisterPairHigh<Register>();
2421 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2422 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002423 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002424 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002425 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2426 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002427
Roland Levillain682393c2015-04-14 15:57:52 +01002428 // temp_d = int-to-double(high)
2429 __ vmovsr(temp_s, high);
2430 __ vcvtdi(temp_d, temp_s);
2431 // constant_d = k2Pow32EncodingForDouble
2432 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2433 // out_d = unsigned-to-double(low)
2434 __ vmovsr(out_s, low);
2435 __ vcvtdu(out_d, out_s);
2436 // out_d += temp_d * constant_d
2437 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002438 break;
2439 }
2440
Roland Levillaincff13742014-11-17 14:32:17 +00002441 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002442 // Processing a Dex `float-to-double' instruction.
2443 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2444 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002445 break;
2446
2447 default:
2448 LOG(FATAL) << "Unexpected type conversion from " << input_type
2449 << " to " << result_type;
2450 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002451 break;
2452
2453 default:
2454 LOG(FATAL) << "Unexpected type conversion from " << input_type
2455 << " to " << result_type;
2456 }
2457}
2458
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002459void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002460 LocationSummary* locations =
2461 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002462 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002463 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002464 locations->SetInAt(0, Location::RequiresRegister());
2465 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002466 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2467 break;
2468 }
2469
2470 case Primitive::kPrimLong: {
2471 locations->SetInAt(0, Location::RequiresRegister());
2472 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002473 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002474 break;
2475 }
2476
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002477 case Primitive::kPrimFloat:
2478 case Primitive::kPrimDouble: {
2479 locations->SetInAt(0, Location::RequiresFpuRegister());
2480 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002481 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002482 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002483 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002484
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002485 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002486 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002487 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002488}
2489
2490void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2491 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002492 Location out = locations->Out();
2493 Location first = locations->InAt(0);
2494 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002495 switch (add->GetResultType()) {
2496 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002497 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002498 __ add(out.AsRegister<Register>(),
2499 first.AsRegister<Register>(),
2500 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002501 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002502 __ AddConstant(out.AsRegister<Register>(),
2503 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002504 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002505 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002506 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002507
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002508 case Primitive::kPrimLong: {
2509 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002510 __ adds(out.AsRegisterPairLow<Register>(),
2511 first.AsRegisterPairLow<Register>(),
2512 ShifterOperand(second.AsRegisterPairLow<Register>()));
2513 __ adc(out.AsRegisterPairHigh<Register>(),
2514 first.AsRegisterPairHigh<Register>(),
2515 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002516 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002517 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002518
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002519 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002520 __ vadds(out.AsFpuRegister<SRegister>(),
2521 first.AsFpuRegister<SRegister>(),
2522 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002523 break;
2524
2525 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002526 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2527 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2528 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002529 break;
2530
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002531 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002532 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002533 }
2534}
2535
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002536void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002537 LocationSummary* locations =
2538 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002539 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002540 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002541 locations->SetInAt(0, Location::RequiresRegister());
2542 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002543 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2544 break;
2545 }
2546
2547 case Primitive::kPrimLong: {
2548 locations->SetInAt(0, Location::RequiresRegister());
2549 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002550 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002551 break;
2552 }
Calin Juravle11351682014-10-23 15:38:15 +01002553 case Primitive::kPrimFloat:
2554 case Primitive::kPrimDouble: {
2555 locations->SetInAt(0, Location::RequiresFpuRegister());
2556 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002557 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002558 break;
Calin Juravle11351682014-10-23 15:38:15 +01002559 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002560 default:
Calin Juravle11351682014-10-23 15:38:15 +01002561 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002562 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002563}
2564
2565void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2566 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002567 Location out = locations->Out();
2568 Location first = locations->InAt(0);
2569 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002570 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002571 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002572 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002573 __ sub(out.AsRegister<Register>(),
2574 first.AsRegister<Register>(),
2575 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002576 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002577 __ AddConstant(out.AsRegister<Register>(),
2578 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002579 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002580 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002581 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002582 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002583
Calin Juravle11351682014-10-23 15:38:15 +01002584 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002585 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002586 __ subs(out.AsRegisterPairLow<Register>(),
2587 first.AsRegisterPairLow<Register>(),
2588 ShifterOperand(second.AsRegisterPairLow<Register>()));
2589 __ sbc(out.AsRegisterPairHigh<Register>(),
2590 first.AsRegisterPairHigh<Register>(),
2591 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002592 break;
Calin Juravle11351682014-10-23 15:38:15 +01002593 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002594
Calin Juravle11351682014-10-23 15:38:15 +01002595 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002596 __ vsubs(out.AsFpuRegister<SRegister>(),
2597 first.AsFpuRegister<SRegister>(),
2598 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002599 break;
Calin Juravle11351682014-10-23 15:38:15 +01002600 }
2601
2602 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002603 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2604 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2605 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002606 break;
2607 }
2608
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002609
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002610 default:
Calin Juravle11351682014-10-23 15:38:15 +01002611 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002612 }
2613}
2614
Calin Juravle34bacdf2014-10-07 20:23:36 +01002615void LocationsBuilderARM::VisitMul(HMul* mul) {
2616 LocationSummary* locations =
2617 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2618 switch (mul->GetResultType()) {
2619 case Primitive::kPrimInt:
2620 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002621 locations->SetInAt(0, Location::RequiresRegister());
2622 locations->SetInAt(1, Location::RequiresRegister());
2623 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002624 break;
2625 }
2626
Calin Juravleb5bfa962014-10-21 18:02:24 +01002627 case Primitive::kPrimFloat:
2628 case Primitive::kPrimDouble: {
2629 locations->SetInAt(0, Location::RequiresFpuRegister());
2630 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002631 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002632 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002633 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002634
2635 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002636 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002637 }
2638}
2639
2640void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2641 LocationSummary* locations = mul->GetLocations();
2642 Location out = locations->Out();
2643 Location first = locations->InAt(0);
2644 Location second = locations->InAt(1);
2645 switch (mul->GetResultType()) {
2646 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002647 __ mul(out.AsRegister<Register>(),
2648 first.AsRegister<Register>(),
2649 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002650 break;
2651 }
2652 case Primitive::kPrimLong: {
2653 Register out_hi = out.AsRegisterPairHigh<Register>();
2654 Register out_lo = out.AsRegisterPairLow<Register>();
2655 Register in1_hi = first.AsRegisterPairHigh<Register>();
2656 Register in1_lo = first.AsRegisterPairLow<Register>();
2657 Register in2_hi = second.AsRegisterPairHigh<Register>();
2658 Register in2_lo = second.AsRegisterPairLow<Register>();
2659
2660 // Extra checks to protect caused by the existence of R1_R2.
2661 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2662 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2663 DCHECK_NE(out_hi, in1_lo);
2664 DCHECK_NE(out_hi, in2_lo);
2665
2666 // input: in1 - 64 bits, in2 - 64 bits
2667 // output: out
2668 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2669 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2670 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2671
2672 // IP <- in1.lo * in2.hi
2673 __ mul(IP, in1_lo, in2_hi);
2674 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2675 __ mla(out_hi, in1_hi, in2_lo, IP);
2676 // out.lo <- (in1.lo * in2.lo)[31:0];
2677 __ umull(out_lo, IP, in1_lo, in2_lo);
2678 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2679 __ add(out_hi, out_hi, ShifterOperand(IP));
2680 break;
2681 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002682
2683 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002684 __ vmuls(out.AsFpuRegister<SRegister>(),
2685 first.AsFpuRegister<SRegister>(),
2686 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002687 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002688 }
2689
2690 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002691 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2692 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2693 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002694 break;
2695 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002696
2697 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002698 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002699 }
2700}
2701
Zheng Xuc6667102015-05-15 16:08:45 +08002702void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2703 DCHECK(instruction->IsDiv() || instruction->IsRem());
2704 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2705
2706 LocationSummary* locations = instruction->GetLocations();
2707 Location second = locations->InAt(1);
2708 DCHECK(second.IsConstant());
2709
2710 Register out = locations->Out().AsRegister<Register>();
2711 Register dividend = locations->InAt(0).AsRegister<Register>();
2712 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2713 DCHECK(imm == 1 || imm == -1);
2714
2715 if (instruction->IsRem()) {
2716 __ LoadImmediate(out, 0);
2717 } else {
2718 if (imm == 1) {
2719 __ Mov(out, dividend);
2720 } else {
2721 __ rsb(out, dividend, ShifterOperand(0));
2722 }
2723 }
2724}
2725
2726void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2727 DCHECK(instruction->IsDiv() || instruction->IsRem());
2728 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2729
2730 LocationSummary* locations = instruction->GetLocations();
2731 Location second = locations->InAt(1);
2732 DCHECK(second.IsConstant());
2733
2734 Register out = locations->Out().AsRegister<Register>();
2735 Register dividend = locations->InAt(0).AsRegister<Register>();
2736 Register temp = locations->GetTemp(0).AsRegister<Register>();
2737 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002738 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002739 int ctz_imm = CTZ(abs_imm);
2740
2741 if (ctz_imm == 1) {
2742 __ Lsr(temp, dividend, 32 - ctz_imm);
2743 } else {
2744 __ Asr(temp, dividend, 31);
2745 __ Lsr(temp, temp, 32 - ctz_imm);
2746 }
2747 __ add(out, temp, ShifterOperand(dividend));
2748
2749 if (instruction->IsDiv()) {
2750 __ Asr(out, out, ctz_imm);
2751 if (imm < 0) {
2752 __ rsb(out, out, ShifterOperand(0));
2753 }
2754 } else {
2755 __ ubfx(out, out, 0, ctz_imm);
2756 __ sub(out, out, ShifterOperand(temp));
2757 }
2758}
2759
2760void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2761 DCHECK(instruction->IsDiv() || instruction->IsRem());
2762 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2763
2764 LocationSummary* locations = instruction->GetLocations();
2765 Location second = locations->InAt(1);
2766 DCHECK(second.IsConstant());
2767
2768 Register out = locations->Out().AsRegister<Register>();
2769 Register dividend = locations->InAt(0).AsRegister<Register>();
2770 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2771 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2772 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2773
2774 int64_t magic;
2775 int shift;
2776 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2777
2778 __ LoadImmediate(temp1, magic);
2779 __ smull(temp2, temp1, dividend, temp1);
2780
2781 if (imm > 0 && magic < 0) {
2782 __ add(temp1, temp1, ShifterOperand(dividend));
2783 } else if (imm < 0 && magic > 0) {
2784 __ sub(temp1, temp1, ShifterOperand(dividend));
2785 }
2786
2787 if (shift != 0) {
2788 __ Asr(temp1, temp1, shift);
2789 }
2790
2791 if (instruction->IsDiv()) {
2792 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2793 } else {
2794 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2795 // TODO: Strength reduction for mls.
2796 __ LoadImmediate(temp2, imm);
2797 __ mls(out, temp1, temp2, dividend);
2798 }
2799}
2800
2801void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2802 DCHECK(instruction->IsDiv() || instruction->IsRem());
2803 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2804
2805 LocationSummary* locations = instruction->GetLocations();
2806 Location second = locations->InAt(1);
2807 DCHECK(second.IsConstant());
2808
2809 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2810 if (imm == 0) {
2811 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2812 } else if (imm == 1 || imm == -1) {
2813 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002814 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002815 DivRemByPowerOfTwo(instruction);
2816 } else {
2817 DCHECK(imm <= -2 || imm >= 2);
2818 GenerateDivRemWithAnyConstant(instruction);
2819 }
2820}
2821
Calin Juravle7c4954d2014-10-28 16:57:40 +00002822void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002823 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2824 if (div->GetResultType() == Primitive::kPrimLong) {
2825 // pLdiv runtime call.
2826 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002827 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2828 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002829 } else if (div->GetResultType() == Primitive::kPrimInt &&
2830 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2831 // pIdivmod runtime call.
2832 call_kind = LocationSummary::kCall;
2833 }
2834
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002835 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2836
Calin Juravle7c4954d2014-10-28 16:57:40 +00002837 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002838 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002839 if (div->InputAt(1)->IsConstant()) {
2840 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002841 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002842 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002843 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
2844 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002845 // No temp register required.
2846 } else {
2847 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002848 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002849 locations->AddTemp(Location::RequiresRegister());
2850 }
2851 }
2852 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002853 locations->SetInAt(0, Location::RequiresRegister());
2854 locations->SetInAt(1, Location::RequiresRegister());
2855 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2856 } else {
2857 InvokeRuntimeCallingConvention calling_convention;
2858 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2859 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2860 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2861 // we only need the former.
2862 locations->SetOut(Location::RegisterLocation(R0));
2863 }
Calin Juravled0d48522014-11-04 16:40:20 +00002864 break;
2865 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002866 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002867 InvokeRuntimeCallingConvention calling_convention;
2868 locations->SetInAt(0, Location::RegisterPairLocation(
2869 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2870 locations->SetInAt(1, Location::RegisterPairLocation(
2871 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002872 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002873 break;
2874 }
2875 case Primitive::kPrimFloat:
2876 case Primitive::kPrimDouble: {
2877 locations->SetInAt(0, Location::RequiresFpuRegister());
2878 locations->SetInAt(1, Location::RequiresFpuRegister());
2879 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2880 break;
2881 }
2882
2883 default:
2884 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2885 }
2886}
2887
2888void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2889 LocationSummary* locations = div->GetLocations();
2890 Location out = locations->Out();
2891 Location first = locations->InAt(0);
2892 Location second = locations->InAt(1);
2893
2894 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002895 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002896 if (second.IsConstant()) {
2897 GenerateDivRemConstantIntegral(div);
2898 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002899 __ sdiv(out.AsRegister<Register>(),
2900 first.AsRegister<Register>(),
2901 second.AsRegister<Register>());
2902 } else {
2903 InvokeRuntimeCallingConvention calling_convention;
2904 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2905 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2906 DCHECK_EQ(R0, out.AsRegister<Register>());
2907
2908 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002909 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002910 }
Calin Juravled0d48522014-11-04 16:40:20 +00002911 break;
2912 }
2913
Calin Juravle7c4954d2014-10-28 16:57:40 +00002914 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002915 InvokeRuntimeCallingConvention calling_convention;
2916 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2917 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2918 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2919 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2920 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002921 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002922
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002923 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002924 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002925 break;
2926 }
2927
2928 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002929 __ vdivs(out.AsFpuRegister<SRegister>(),
2930 first.AsFpuRegister<SRegister>(),
2931 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002932 break;
2933 }
2934
2935 case Primitive::kPrimDouble: {
2936 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2937 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2938 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2939 break;
2940 }
2941
2942 default:
2943 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2944 }
2945}
2946
Calin Juravlebacfec32014-11-14 15:54:36 +00002947void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002948 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002949
2950 // Most remainders are implemented in the runtime.
2951 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002952 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2953 // sdiv will be replaced by other instruction sequence.
2954 call_kind = LocationSummary::kNoCall;
2955 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2956 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002957 // Have hardware divide instruction for int, do it with three instructions.
2958 call_kind = LocationSummary::kNoCall;
2959 }
2960
Calin Juravlebacfec32014-11-14 15:54:36 +00002961 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2962
Calin Juravled2ec87d2014-12-08 14:24:46 +00002963 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002964 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002965 if (rem->InputAt(1)->IsConstant()) {
2966 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002967 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002968 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002969 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
2970 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002971 // No temp register required.
2972 } else {
2973 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002974 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002975 locations->AddTemp(Location::RequiresRegister());
2976 }
2977 }
2978 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002979 locations->SetInAt(0, Location::RequiresRegister());
2980 locations->SetInAt(1, Location::RequiresRegister());
2981 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2982 locations->AddTemp(Location::RequiresRegister());
2983 } else {
2984 InvokeRuntimeCallingConvention calling_convention;
2985 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2986 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2987 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2988 // we only need the latter.
2989 locations->SetOut(Location::RegisterLocation(R1));
2990 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002991 break;
2992 }
2993 case Primitive::kPrimLong: {
2994 InvokeRuntimeCallingConvention calling_convention;
2995 locations->SetInAt(0, Location::RegisterPairLocation(
2996 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2997 locations->SetInAt(1, Location::RegisterPairLocation(
2998 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2999 // The runtime helper puts the output in R2,R3.
3000 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3001 break;
3002 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003003 case Primitive::kPrimFloat: {
3004 InvokeRuntimeCallingConvention calling_convention;
3005 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3006 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3007 locations->SetOut(Location::FpuRegisterLocation(S0));
3008 break;
3009 }
3010
Calin Juravlebacfec32014-11-14 15:54:36 +00003011 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003012 InvokeRuntimeCallingConvention calling_convention;
3013 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3014 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3015 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3016 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3017 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003018 break;
3019 }
3020
3021 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003022 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003023 }
3024}
3025
3026void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3027 LocationSummary* locations = rem->GetLocations();
3028 Location out = locations->Out();
3029 Location first = locations->InAt(0);
3030 Location second = locations->InAt(1);
3031
Calin Juravled2ec87d2014-12-08 14:24:46 +00003032 Primitive::Type type = rem->GetResultType();
3033 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003034 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003035 if (second.IsConstant()) {
3036 GenerateDivRemConstantIntegral(rem);
3037 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003038 Register reg1 = first.AsRegister<Register>();
3039 Register reg2 = second.AsRegister<Register>();
3040 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003041
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003042 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003043 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003044 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003045 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003046 } else {
3047 InvokeRuntimeCallingConvention calling_convention;
3048 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3049 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3050 DCHECK_EQ(R1, out.AsRegister<Register>());
3051
3052 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003053 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003054 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003055 break;
3056 }
3057
3058 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003059 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003060 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003061 break;
3062 }
3063
Calin Juravled2ec87d2014-12-08 14:24:46 +00003064 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003065 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003066 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003067 break;
3068 }
3069
Calin Juravlebacfec32014-11-14 15:54:36 +00003070 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003071 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003072 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003073 break;
3074 }
3075
3076 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003077 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003078 }
3079}
3080
Calin Juravled0d48522014-11-04 16:40:20 +00003081void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003082 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3083 ? LocationSummary::kCallOnSlowPath
3084 : LocationSummary::kNoCall;
3085 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003086 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003087 if (instruction->HasUses()) {
3088 locations->SetOut(Location::SameAsFirstInput());
3089 }
3090}
3091
3092void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003093 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003094 codegen_->AddSlowPath(slow_path);
3095
3096 LocationSummary* locations = instruction->GetLocations();
3097 Location value = locations->InAt(0);
3098
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003099 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003100 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003101 case Primitive::kPrimByte:
3102 case Primitive::kPrimChar:
3103 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003104 case Primitive::kPrimInt: {
3105 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003106 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003107 } else {
3108 DCHECK(value.IsConstant()) << value;
3109 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3110 __ b(slow_path->GetEntryLabel());
3111 }
3112 }
3113 break;
3114 }
3115 case Primitive::kPrimLong: {
3116 if (value.IsRegisterPair()) {
3117 __ orrs(IP,
3118 value.AsRegisterPairLow<Register>(),
3119 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3120 __ b(slow_path->GetEntryLabel(), EQ);
3121 } else {
3122 DCHECK(value.IsConstant()) << value;
3123 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3124 __ b(slow_path->GetEntryLabel());
3125 }
3126 }
3127 break;
3128 default:
3129 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3130 }
3131 }
Calin Juravled0d48522014-11-04 16:40:20 +00003132}
3133
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003134void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3135 Register in = locations->InAt(0).AsRegister<Register>();
3136 Location rhs = locations->InAt(1);
3137 Register out = locations->Out().AsRegister<Register>();
3138
3139 if (rhs.IsConstant()) {
3140 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3141 // so map all rotations to a +ve. equivalent in that range.
3142 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3143 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3144 if (rot) {
3145 // Rotate, mapping left rotations to right equivalents if necessary.
3146 // (e.g. left by 2 bits == right by 30.)
3147 __ Ror(out, in, rot);
3148 } else if (out != in) {
3149 __ Mov(out, in);
3150 }
3151 } else {
3152 __ Ror(out, in, rhs.AsRegister<Register>());
3153 }
3154}
3155
3156// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3157// rotates by swapping input regs (effectively rotating by the first 32-bits of
3158// a larger rotation) or flipping direction (thus treating larger right/left
3159// rotations as sub-word sized rotations in the other direction) as appropriate.
3160void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3161 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3162 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3163 Location rhs = locations->InAt(1);
3164 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3165 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3166
3167 if (rhs.IsConstant()) {
3168 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3169 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003170 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003171 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3172 // logic below to a simple pair of binary orr.
3173 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3174 if (rot >= kArmBitsPerWord) {
3175 rot -= kArmBitsPerWord;
3176 std::swap(in_reg_hi, in_reg_lo);
3177 }
3178 // Rotate, or mov to out for zero or word size rotations.
3179 if (rot != 0u) {
3180 __ Lsr(out_reg_hi, in_reg_hi, rot);
3181 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3182 __ Lsr(out_reg_lo, in_reg_lo, rot);
3183 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3184 } else {
3185 __ Mov(out_reg_lo, in_reg_lo);
3186 __ Mov(out_reg_hi, in_reg_hi);
3187 }
3188 } else {
3189 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3190 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3191 Label end;
3192 Label shift_by_32_plus_shift_right;
3193
3194 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3195 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3196 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3197 __ b(&shift_by_32_plus_shift_right, CC);
3198
3199 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3200 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3201 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3202 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3203 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3204 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3205 __ Lsr(shift_left, in_reg_hi, shift_right);
3206 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3207 __ b(&end);
3208
3209 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3210 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3211 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3212 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3213 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3214 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3215 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3216 __ Lsl(shift_right, in_reg_hi, shift_left);
3217 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3218
3219 __ Bind(&end);
3220 }
3221}
Roland Levillain22c49222016-03-18 14:04:28 +00003222
3223void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003224 LocationSummary* locations =
3225 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3226 switch (ror->GetResultType()) {
3227 case Primitive::kPrimInt: {
3228 locations->SetInAt(0, Location::RequiresRegister());
3229 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3230 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3231 break;
3232 }
3233 case Primitive::kPrimLong: {
3234 locations->SetInAt(0, Location::RequiresRegister());
3235 if (ror->InputAt(1)->IsConstant()) {
3236 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3237 } else {
3238 locations->SetInAt(1, Location::RequiresRegister());
3239 locations->AddTemp(Location::RequiresRegister());
3240 locations->AddTemp(Location::RequiresRegister());
3241 }
3242 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3243 break;
3244 }
3245 default:
3246 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3247 }
3248}
3249
Roland Levillain22c49222016-03-18 14:04:28 +00003250void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003251 LocationSummary* locations = ror->GetLocations();
3252 Primitive::Type type = ror->GetResultType();
3253 switch (type) {
3254 case Primitive::kPrimInt: {
3255 HandleIntegerRotate(locations);
3256 break;
3257 }
3258 case Primitive::kPrimLong: {
3259 HandleLongRotate(locations);
3260 break;
3261 }
3262 default:
3263 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003264 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003265 }
3266}
3267
Calin Juravle9aec02f2014-11-18 23:06:35 +00003268void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3269 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3270
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003271 LocationSummary* locations =
3272 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003273
3274 switch (op->GetResultType()) {
3275 case Primitive::kPrimInt: {
3276 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003277 if (op->InputAt(1)->IsConstant()) {
3278 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3279 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3280 } else {
3281 locations->SetInAt(1, Location::RequiresRegister());
3282 // Make the output overlap, as it will be used to hold the masked
3283 // second input.
3284 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3285 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003286 break;
3287 }
3288 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003289 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003290 if (op->InputAt(1)->IsConstant()) {
3291 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3292 // For simplicity, use kOutputOverlap even though we only require that low registers
3293 // don't clash with high registers which the register allocator currently guarantees.
3294 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3295 } else {
3296 locations->SetInAt(1, Location::RequiresRegister());
3297 locations->AddTemp(Location::RequiresRegister());
3298 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3299 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003300 break;
3301 }
3302 default:
3303 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3304 }
3305}
3306
3307void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3308 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3309
3310 LocationSummary* locations = op->GetLocations();
3311 Location out = locations->Out();
3312 Location first = locations->InAt(0);
3313 Location second = locations->InAt(1);
3314
3315 Primitive::Type type = op->GetResultType();
3316 switch (type) {
3317 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003318 Register out_reg = out.AsRegister<Register>();
3319 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003320 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003321 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003322 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003323 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003324 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003325 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003326 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003327 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003328 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003329 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003330 }
3331 } else {
3332 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003333 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003334 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003335 __ Mov(out_reg, first_reg);
3336 } else if (op->IsShl()) {
3337 __ Lsl(out_reg, first_reg, shift_value);
3338 } else if (op->IsShr()) {
3339 __ Asr(out_reg, first_reg, shift_value);
3340 } else {
3341 __ Lsr(out_reg, first_reg, shift_value);
3342 }
3343 }
3344 break;
3345 }
3346 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003347 Register o_h = out.AsRegisterPairHigh<Register>();
3348 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003349
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003350 Register high = first.AsRegisterPairHigh<Register>();
3351 Register low = first.AsRegisterPairLow<Register>();
3352
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003353 if (second.IsRegister()) {
3354 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003355
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003356 Register second_reg = second.AsRegister<Register>();
3357
3358 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003359 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003360 // Shift the high part
3361 __ Lsl(o_h, high, o_l);
3362 // Shift the low part and `or` what overflew on the high part
3363 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3364 __ Lsr(temp, low, temp);
3365 __ orr(o_h, o_h, ShifterOperand(temp));
3366 // If the shift is > 32 bits, override the high part
3367 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3368 __ it(PL);
3369 __ Lsl(o_h, low, temp, PL);
3370 // Shift the low part
3371 __ Lsl(o_l, low, o_l);
3372 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003373 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003374 // Shift the low part
3375 __ Lsr(o_l, low, o_h);
3376 // Shift the high part and `or` what underflew on the low part
3377 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3378 __ Lsl(temp, high, temp);
3379 __ orr(o_l, o_l, ShifterOperand(temp));
3380 // If the shift is > 32 bits, override the low part
3381 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3382 __ it(PL);
3383 __ Asr(o_l, high, temp, PL);
3384 // Shift the high part
3385 __ Asr(o_h, high, o_h);
3386 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003387 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003388 // same as Shr except we use `Lsr`s and not `Asr`s
3389 __ Lsr(o_l, low, o_h);
3390 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3391 __ Lsl(temp, high, temp);
3392 __ orr(o_l, o_l, ShifterOperand(temp));
3393 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3394 __ it(PL);
3395 __ Lsr(o_l, high, temp, PL);
3396 __ Lsr(o_h, high, o_h);
3397 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003398 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003399 // Register allocator doesn't create partial overlap.
3400 DCHECK_NE(o_l, high);
3401 DCHECK_NE(o_h, low);
3402 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003403 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003404 if (shift_value > 32) {
3405 if (op->IsShl()) {
3406 __ Lsl(o_h, low, shift_value - 32);
3407 __ LoadImmediate(o_l, 0);
3408 } else if (op->IsShr()) {
3409 __ Asr(o_l, high, shift_value - 32);
3410 __ Asr(o_h, high, 31);
3411 } else {
3412 __ Lsr(o_l, high, shift_value - 32);
3413 __ LoadImmediate(o_h, 0);
3414 }
3415 } else if (shift_value == 32) {
3416 if (op->IsShl()) {
3417 __ mov(o_h, ShifterOperand(low));
3418 __ LoadImmediate(o_l, 0);
3419 } else if (op->IsShr()) {
3420 __ mov(o_l, ShifterOperand(high));
3421 __ Asr(o_h, high, 31);
3422 } else {
3423 __ mov(o_l, ShifterOperand(high));
3424 __ LoadImmediate(o_h, 0);
3425 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003426 } else if (shift_value == 1) {
3427 if (op->IsShl()) {
3428 __ Lsls(o_l, low, 1);
3429 __ adc(o_h, high, ShifterOperand(high));
3430 } else if (op->IsShr()) {
3431 __ Asrs(o_h, high, 1);
3432 __ Rrx(o_l, low);
3433 } else {
3434 __ Lsrs(o_h, high, 1);
3435 __ Rrx(o_l, low);
3436 }
3437 } else {
3438 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003439 if (op->IsShl()) {
3440 __ Lsl(o_h, high, shift_value);
3441 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3442 __ Lsl(o_l, low, shift_value);
3443 } else if (op->IsShr()) {
3444 __ Lsr(o_l, low, shift_value);
3445 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3446 __ Asr(o_h, high, shift_value);
3447 } else {
3448 __ Lsr(o_l, low, shift_value);
3449 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3450 __ Lsr(o_h, high, shift_value);
3451 }
3452 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003453 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003454 break;
3455 }
3456 default:
3457 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003458 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003459 }
3460}
3461
3462void LocationsBuilderARM::VisitShl(HShl* shl) {
3463 HandleShift(shl);
3464}
3465
3466void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3467 HandleShift(shl);
3468}
3469
3470void LocationsBuilderARM::VisitShr(HShr* shr) {
3471 HandleShift(shr);
3472}
3473
3474void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3475 HandleShift(shr);
3476}
3477
3478void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3479 HandleShift(ushr);
3480}
3481
3482void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3483 HandleShift(ushr);
3484}
3485
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003486void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003487 LocationSummary* locations =
3488 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
David Brazdil6de19382016-01-08 17:37:10 +00003489 if (instruction->IsStringAlloc()) {
3490 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3491 } else {
3492 InvokeRuntimeCallingConvention calling_convention;
3493 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3494 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3495 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003496 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003497}
3498
3499void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003500 // Note: if heap poisoning is enabled, the entry point takes cares
3501 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003502 if (instruction->IsStringAlloc()) {
3503 // String is allocated through StringFactory. Call NewEmptyString entry point.
3504 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
3505 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
3506 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3507 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3508 __ blx(LR);
3509 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3510 } else {
3511 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3512 instruction,
3513 instruction->GetDexPc(),
3514 nullptr);
3515 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3516 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003517}
3518
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003519void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3520 LocationSummary* locations =
3521 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3522 InvokeRuntimeCallingConvention calling_convention;
3523 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003524 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003525 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003526 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003527}
3528
3529void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3530 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003531 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003532 // Note: if heap poisoning is enabled, the entry point takes cares
3533 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003534 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003535 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003536 instruction->GetDexPc(),
3537 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003538 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003539}
3540
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003541void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003542 LocationSummary* locations =
3543 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003544 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3545 if (location.IsStackSlot()) {
3546 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3547 } else if (location.IsDoubleStackSlot()) {
3548 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003549 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003550 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003551}
3552
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003553void InstructionCodeGeneratorARM::VisitParameterValue(
3554 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003555 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003556}
3557
3558void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3559 LocationSummary* locations =
3560 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3561 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3562}
3563
3564void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3565 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003566}
3567
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003568void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003569 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003570 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003571 locations->SetInAt(0, Location::RequiresRegister());
3572 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003573}
3574
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003575void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3576 LocationSummary* locations = not_->GetLocations();
3577 Location out = locations->Out();
3578 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003579 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003580 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003581 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003582 break;
3583
3584 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003585 __ mvn(out.AsRegisterPairLow<Register>(),
3586 ShifterOperand(in.AsRegisterPairLow<Register>()));
3587 __ mvn(out.AsRegisterPairHigh<Register>(),
3588 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003589 break;
3590
3591 default:
3592 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3593 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003594}
3595
David Brazdil66d126e2015-04-03 16:02:44 +01003596void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3597 LocationSummary* locations =
3598 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3599 locations->SetInAt(0, Location::RequiresRegister());
3600 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3601}
3602
3603void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003604 LocationSummary* locations = bool_not->GetLocations();
3605 Location out = locations->Out();
3606 Location in = locations->InAt(0);
3607 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3608}
3609
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003610void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003611 LocationSummary* locations =
3612 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003613 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003614 case Primitive::kPrimBoolean:
3615 case Primitive::kPrimByte:
3616 case Primitive::kPrimShort:
3617 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003618 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00003619 case Primitive::kPrimLong: {
3620 locations->SetInAt(0, Location::RequiresRegister());
3621 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003622 // Output overlaps because it is written before doing the low comparison.
3623 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003624 break;
3625 }
3626 case Primitive::kPrimFloat:
3627 case Primitive::kPrimDouble: {
3628 locations->SetInAt(0, Location::RequiresFpuRegister());
3629 locations->SetInAt(1, Location::RequiresFpuRegister());
3630 locations->SetOut(Location::RequiresRegister());
3631 break;
3632 }
3633 default:
3634 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3635 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003636}
3637
3638void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003639 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003640 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003641 Location left = locations->InAt(0);
3642 Location right = locations->InAt(1);
3643
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003644 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003645 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00003646 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00003647 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003648 case Primitive::kPrimBoolean:
3649 case Primitive::kPrimByte:
3650 case Primitive::kPrimShort:
3651 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003652 case Primitive::kPrimInt: {
3653 __ LoadImmediate(out, 0);
3654 __ cmp(left.AsRegister<Register>(),
3655 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
3656 less_cond = LT;
3657 break;
3658 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003659 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003660 __ cmp(left.AsRegisterPairHigh<Register>(),
3661 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003662 __ b(&less, LT);
3663 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003664 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003665 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003666 __ cmp(left.AsRegisterPairLow<Register>(),
3667 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003668 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00003669 break;
3670 }
3671 case Primitive::kPrimFloat:
3672 case Primitive::kPrimDouble: {
3673 __ LoadImmediate(out, 0);
3674 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003675 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003676 } else {
3677 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3678 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3679 }
3680 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003681 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003682 break;
3683 }
3684 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003685 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00003686 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003687 }
Aart Bika19616e2016-02-01 18:57:58 -08003688
Calin Juravleddb7df22014-11-25 20:56:51 +00003689 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00003690 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00003691
3692 __ Bind(&greater);
3693 __ LoadImmediate(out, 1);
3694 __ b(&done);
3695
3696 __ Bind(&less);
3697 __ LoadImmediate(out, -1);
3698
3699 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003700}
3701
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003702void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003703 LocationSummary* locations =
3704 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01003705 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003706 locations->SetInAt(i, Location::Any());
3707 }
3708 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003709}
3710
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003711void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003712 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003713}
3714
Roland Levillainc9285912015-12-18 10:38:42 +00003715void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3716 // TODO (ported from quick): revisit ARM barrier kinds.
3717 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00003718 switch (kind) {
3719 case MemBarrierKind::kAnyStore:
3720 case MemBarrierKind::kLoadAny:
3721 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003722 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003723 break;
3724 }
3725 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003726 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003727 break;
3728 }
3729 default:
3730 LOG(FATAL) << "Unexpected memory barrier " << kind;
3731 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003732 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003733}
3734
3735void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3736 uint32_t offset,
3737 Register out_lo,
3738 Register out_hi) {
3739 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003740 // Ensure `out_lo` is different from `addr`, so that loading
3741 // `offset` into `out_lo` does not clutter `addr`.
3742 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003743 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003744 __ add(IP, addr, ShifterOperand(out_lo));
3745 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003746 }
3747 __ ldrexd(out_lo, out_hi, addr);
3748}
3749
3750void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3751 uint32_t offset,
3752 Register value_lo,
3753 Register value_hi,
3754 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003755 Register temp2,
3756 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003757 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003758 if (offset != 0) {
3759 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003760 __ add(IP, addr, ShifterOperand(temp1));
3761 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003762 }
3763 __ Bind(&fail);
3764 // We need a load followed by store. (The address used in a STREX instruction must
3765 // be the same as the address in the most recently executed LDREX instruction.)
3766 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003767 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003768 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003769 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003770}
3771
3772void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3773 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3774
Nicolas Geoffray39468442014-09-02 15:17:15 +01003775 LocationSummary* locations =
3776 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003777 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003778
Calin Juravle52c48962014-12-16 17:02:57 +00003779 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003780 if (Primitive::IsFloatingPointType(field_type)) {
3781 locations->SetInAt(1, Location::RequiresFpuRegister());
3782 } else {
3783 locations->SetInAt(1, Location::RequiresRegister());
3784 }
3785
Calin Juravle52c48962014-12-16 17:02:57 +00003786 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003787 bool generate_volatile = field_info.IsVolatile()
3788 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003789 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003790 bool needs_write_barrier =
3791 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003792 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003793 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003794 if (needs_write_barrier) {
3795 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003796 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003797 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003798 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003799 // - registers need to be consecutive
3800 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003801 // We don't test for ARM yet, and the assertion makes sure that we
3802 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003803 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3804
3805 locations->AddTemp(Location::RequiresRegister());
3806 locations->AddTemp(Location::RequiresRegister());
3807 if (field_type == Primitive::kPrimDouble) {
3808 // For doubles we need two more registers to copy the value.
3809 locations->AddTemp(Location::RegisterLocation(R2));
3810 locations->AddTemp(Location::RegisterLocation(R3));
3811 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003812 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003813}
3814
Calin Juravle52c48962014-12-16 17:02:57 +00003815void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003816 const FieldInfo& field_info,
3817 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003818 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3819
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003820 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003821 Register base = locations->InAt(0).AsRegister<Register>();
3822 Location value = locations->InAt(1);
3823
3824 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003825 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003826 Primitive::Type field_type = field_info.GetFieldType();
3827 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003828 bool needs_write_barrier =
3829 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003830
3831 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003832 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00003833 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003834
3835 switch (field_type) {
3836 case Primitive::kPrimBoolean:
3837 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003838 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003839 break;
3840 }
3841
3842 case Primitive::kPrimShort:
3843 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003844 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003845 break;
3846 }
3847
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003848 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003849 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003850 if (kPoisonHeapReferences && needs_write_barrier) {
3851 // Note that in the case where `value` is a null reference,
3852 // we do not enter this block, as a null reference does not
3853 // need poisoning.
3854 DCHECK_EQ(field_type, Primitive::kPrimNot);
3855 Register temp = locations->GetTemp(0).AsRegister<Register>();
3856 __ Mov(temp, value.AsRegister<Register>());
3857 __ PoisonHeapReference(temp);
3858 __ StoreToOffset(kStoreWord, temp, base, offset);
3859 } else {
3860 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3861 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003862 break;
3863 }
3864
3865 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003866 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003867 GenerateWideAtomicStore(base, offset,
3868 value.AsRegisterPairLow<Register>(),
3869 value.AsRegisterPairHigh<Register>(),
3870 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003871 locations->GetTemp(1).AsRegister<Register>(),
3872 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003873 } else {
3874 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003875 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003876 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003877 break;
3878 }
3879
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003880 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003881 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003882 break;
3883 }
3884
3885 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003886 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003887 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003888 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3889 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3890
3891 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3892
3893 GenerateWideAtomicStore(base, offset,
3894 value_reg_lo,
3895 value_reg_hi,
3896 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003897 locations->GetTemp(3).AsRegister<Register>(),
3898 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003899 } else {
3900 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003901 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003902 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003903 break;
3904 }
3905
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003906 case Primitive::kPrimVoid:
3907 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003908 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003909 }
Calin Juravle52c48962014-12-16 17:02:57 +00003910
Calin Juravle77520bc2015-01-12 18:45:46 +00003911 // Longs and doubles are handled in the switch.
3912 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3913 codegen_->MaybeRecordImplicitNullCheck(instruction);
3914 }
3915
3916 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3917 Register temp = locations->GetTemp(0).AsRegister<Register>();
3918 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003919 codegen_->MarkGCCard(
3920 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003921 }
3922
Calin Juravle52c48962014-12-16 17:02:57 +00003923 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003924 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00003925 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003926}
3927
Calin Juravle52c48962014-12-16 17:02:57 +00003928void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3929 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003930
3931 bool object_field_get_with_read_barrier =
3932 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003933 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003934 new (GetGraph()->GetArena()) LocationSummary(instruction,
3935 object_field_get_with_read_barrier ?
3936 LocationSummary::kCallOnSlowPath :
3937 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003938 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003939
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003940 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003941 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003942 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00003943 // The output overlaps in case of volatile long: we don't want the
3944 // code generated by GenerateWideAtomicLoad to overwrite the
3945 // object's location. Likewise, in the case of an object field get
3946 // with read barriers enabled, we do not want the load to overwrite
3947 // the object's location, as we need it to emit the read barrier.
3948 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
3949 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003950
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003951 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3952 locations->SetOut(Location::RequiresFpuRegister());
3953 } else {
3954 locations->SetOut(Location::RequiresRegister(),
3955 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3956 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003957 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00003958 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003959 // - registers need to be consecutive
3960 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003961 // We don't test for ARM yet, and the assertion makes sure that we
3962 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003963 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3964 locations->AddTemp(Location::RequiresRegister());
3965 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00003966 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
3967 // We need a temporary register for the read barrier marking slow
3968 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
3969 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003970 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003971}
3972
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003973Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3974 Opcode opcode) {
3975 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3976 if (constant->IsConstant() &&
3977 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3978 return Location::ConstantLocation(constant->AsConstant());
3979 }
3980 return Location::RequiresRegister();
3981}
3982
3983bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3984 Opcode opcode) {
3985 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3986 if (Primitive::Is64BitType(input_cst->GetType())) {
3987 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3988 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3989 } else {
3990 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3991 }
3992}
3993
3994bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
3995 ShifterOperand so;
3996 ArmAssembler* assembler = codegen_->GetAssembler();
3997 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
3998 return true;
3999 }
4000 Opcode neg_opcode = kNoOperand;
4001 switch (opcode) {
4002 case AND:
4003 neg_opcode = BIC;
4004 break;
4005 case ORR:
4006 neg_opcode = ORN;
4007 break;
4008 default:
4009 return false;
4010 }
4011 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4012}
4013
Calin Juravle52c48962014-12-16 17:02:57 +00004014void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4015 const FieldInfo& field_info) {
4016 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004017
Calin Juravle52c48962014-12-16 17:02:57 +00004018 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004019 Location base_loc = locations->InAt(0);
4020 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004021 Location out = locations->Out();
4022 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004023 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004024 Primitive::Type field_type = field_info.GetFieldType();
4025 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4026
4027 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004028 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004029 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004030 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004031
Roland Levillainc9285912015-12-18 10:38:42 +00004032 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004033 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004034 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004035
Roland Levillainc9285912015-12-18 10:38:42 +00004036 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004037 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004038 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004039
Roland Levillainc9285912015-12-18 10:38:42 +00004040 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004041 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004042 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004043
4044 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004045 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004046 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004047
4048 case Primitive::kPrimNot: {
4049 // /* HeapReference<Object> */ out = *(base + offset)
4050 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4051 Location temp_loc = locations->GetTemp(0);
4052 // Note that a potential implicit null check is handled in this
4053 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4054 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4055 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4056 if (is_volatile) {
4057 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4058 }
4059 } else {
4060 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4061 codegen_->MaybeRecordImplicitNullCheck(instruction);
4062 if (is_volatile) {
4063 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4064 }
4065 // If read barriers are enabled, emit read barriers other than
4066 // Baker's using a slow path (and also unpoison the loaded
4067 // reference, if heap poisoning is enabled).
4068 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4069 }
4070 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004071 }
4072
Roland Levillainc9285912015-12-18 10:38:42 +00004073 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004074 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004075 GenerateWideAtomicLoad(base, offset,
4076 out.AsRegisterPairLow<Register>(),
4077 out.AsRegisterPairHigh<Register>());
4078 } else {
4079 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4080 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004081 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004082
Roland Levillainc9285912015-12-18 10:38:42 +00004083 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004084 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004085 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004086
4087 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004088 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004089 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004090 Register lo = locations->GetTemp(0).AsRegister<Register>();
4091 Register hi = locations->GetTemp(1).AsRegister<Register>();
4092 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004093 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004094 __ vmovdrr(out_reg, lo, hi);
4095 } else {
4096 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004097 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004098 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004099 break;
4100 }
4101
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004102 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004103 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004104 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004105 }
Calin Juravle52c48962014-12-16 17:02:57 +00004106
Roland Levillainc9285912015-12-18 10:38:42 +00004107 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4108 // Potential implicit null checks, in the case of reference or
4109 // double fields, are handled in the previous switch statement.
4110 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004111 codegen_->MaybeRecordImplicitNullCheck(instruction);
4112 }
4113
Calin Juravle52c48962014-12-16 17:02:57 +00004114 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004115 if (field_type == Primitive::kPrimNot) {
4116 // Memory barriers, in the case of references, are also handled
4117 // in the previous switch statement.
4118 } else {
4119 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4120 }
Roland Levillain4d027112015-07-01 15:41:14 +01004121 }
Calin Juravle52c48962014-12-16 17:02:57 +00004122}
4123
4124void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4125 HandleFieldSet(instruction, instruction->GetFieldInfo());
4126}
4127
4128void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004129 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004130}
4131
4132void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4133 HandleFieldGet(instruction, instruction->GetFieldInfo());
4134}
4135
4136void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4137 HandleFieldGet(instruction, instruction->GetFieldInfo());
4138}
4139
4140void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4141 HandleFieldGet(instruction, instruction->GetFieldInfo());
4142}
4143
4144void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4145 HandleFieldGet(instruction, instruction->GetFieldInfo());
4146}
4147
4148void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4149 HandleFieldSet(instruction, instruction->GetFieldInfo());
4150}
4151
4152void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004153 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004154}
4155
Calin Juravlee460d1d2015-09-29 04:52:17 +01004156void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4157 HUnresolvedInstanceFieldGet* instruction) {
4158 FieldAccessCallingConventionARM calling_convention;
4159 codegen_->CreateUnresolvedFieldLocationSummary(
4160 instruction, instruction->GetFieldType(), calling_convention);
4161}
4162
4163void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4164 HUnresolvedInstanceFieldGet* instruction) {
4165 FieldAccessCallingConventionARM calling_convention;
4166 codegen_->GenerateUnresolvedFieldAccess(instruction,
4167 instruction->GetFieldType(),
4168 instruction->GetFieldIndex(),
4169 instruction->GetDexPc(),
4170 calling_convention);
4171}
4172
4173void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4174 HUnresolvedInstanceFieldSet* instruction) {
4175 FieldAccessCallingConventionARM calling_convention;
4176 codegen_->CreateUnresolvedFieldLocationSummary(
4177 instruction, instruction->GetFieldType(), calling_convention);
4178}
4179
4180void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4181 HUnresolvedInstanceFieldSet* instruction) {
4182 FieldAccessCallingConventionARM calling_convention;
4183 codegen_->GenerateUnresolvedFieldAccess(instruction,
4184 instruction->GetFieldType(),
4185 instruction->GetFieldIndex(),
4186 instruction->GetDexPc(),
4187 calling_convention);
4188}
4189
4190void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4191 HUnresolvedStaticFieldGet* instruction) {
4192 FieldAccessCallingConventionARM calling_convention;
4193 codegen_->CreateUnresolvedFieldLocationSummary(
4194 instruction, instruction->GetFieldType(), calling_convention);
4195}
4196
4197void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4198 HUnresolvedStaticFieldGet* instruction) {
4199 FieldAccessCallingConventionARM calling_convention;
4200 codegen_->GenerateUnresolvedFieldAccess(instruction,
4201 instruction->GetFieldType(),
4202 instruction->GetFieldIndex(),
4203 instruction->GetDexPc(),
4204 calling_convention);
4205}
4206
4207void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4208 HUnresolvedStaticFieldSet* instruction) {
4209 FieldAccessCallingConventionARM calling_convention;
4210 codegen_->CreateUnresolvedFieldLocationSummary(
4211 instruction, instruction->GetFieldType(), calling_convention);
4212}
4213
4214void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4215 HUnresolvedStaticFieldSet* instruction) {
4216 FieldAccessCallingConventionARM calling_convention;
4217 codegen_->GenerateUnresolvedFieldAccess(instruction,
4218 instruction->GetFieldType(),
4219 instruction->GetFieldIndex(),
4220 instruction->GetDexPc(),
4221 calling_convention);
4222}
4223
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004224void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004225 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4226 ? LocationSummary::kCallOnSlowPath
4227 : LocationSummary::kNoCall;
4228 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004229 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004230 if (instruction->HasUses()) {
4231 locations->SetOut(Location::SameAsFirstInput());
4232 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004233}
4234
Calin Juravle2ae48182016-03-16 14:05:09 +00004235void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4236 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004237 return;
4238 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004239 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004240
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004241 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004242 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004243}
4244
Calin Juravle2ae48182016-03-16 14:05:09 +00004245void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004246 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004247 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004248
4249 LocationSummary* locations = instruction->GetLocations();
4250 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004251
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004252 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004253}
4254
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004255void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004256 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004257}
4258
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004259void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004260 bool object_array_get_with_read_barrier =
4261 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004262 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004263 new (GetGraph()->GetArena()) LocationSummary(instruction,
4264 object_array_get_with_read_barrier ?
4265 LocationSummary::kCallOnSlowPath :
4266 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004267 locations->SetInAt(0, Location::RequiresRegister());
4268 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004269 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4270 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4271 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004272 // The output overlaps in the case of an object array get with
4273 // read barriers enabled: we do not want the move to overwrite the
4274 // array's location, as we need it to emit the read barrier.
4275 locations->SetOut(
4276 Location::RequiresRegister(),
4277 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004278 }
Roland Levillainc9285912015-12-18 10:38:42 +00004279 // We need a temporary register for the read barrier marking slow
4280 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4281 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4282 locations->AddTemp(Location::RequiresRegister());
4283 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004284}
4285
4286void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4287 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004288 Location obj_loc = locations->InAt(0);
4289 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004290 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004291 Location out_loc = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004292
Roland Levillainc9285912015-12-18 10:38:42 +00004293 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004294 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004295 case Primitive::kPrimBoolean: {
4296 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004297 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004298 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004299 size_t offset =
4300 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004301 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4302 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004303 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004304 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4305 }
4306 break;
4307 }
4308
4309 case Primitive::kPrimByte: {
4310 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004311 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004312 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004313 size_t offset =
4314 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004315 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4316 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004317 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004318 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4319 }
4320 break;
4321 }
4322
4323 case Primitive::kPrimShort: {
4324 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004325 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004326 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004327 size_t offset =
4328 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004329 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4330 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004331 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004332 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4333 }
4334 break;
4335 }
4336
4337 case Primitive::kPrimChar: {
4338 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004339 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004340 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004341 size_t offset =
4342 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004343 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4344 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004345 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004346 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4347 }
4348 break;
4349 }
4350
Roland Levillainc9285912015-12-18 10:38:42 +00004351 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004352 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004353 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004354 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004355 size_t offset =
4356 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004357 __ LoadFromOffset(kLoadWord, out, obj, offset);
4358 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004359 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004360 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4361 }
4362 break;
4363 }
4364
Roland Levillainc9285912015-12-18 10:38:42 +00004365 case Primitive::kPrimNot: {
4366 static_assert(
4367 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4368 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4369 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4370 // /* HeapReference<Object> */ out =
4371 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4372 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4373 Location temp = locations->GetTemp(0);
4374 // Note that a potential implicit null check is handled in this
4375 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4376 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4377 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4378 } else {
4379 Register out = out_loc.AsRegister<Register>();
4380 if (index.IsConstant()) {
4381 size_t offset =
4382 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4383 __ LoadFromOffset(kLoadWord, out, obj, offset);
4384 codegen_->MaybeRecordImplicitNullCheck(instruction);
4385 // If read barriers are enabled, emit read barriers other than
4386 // Baker's using a slow path (and also unpoison the loaded
4387 // reference, if heap poisoning is enabled).
4388 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4389 } else {
4390 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4391 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4392 codegen_->MaybeRecordImplicitNullCheck(instruction);
4393 // If read barriers are enabled, emit read barriers other than
4394 // Baker's using a slow path (and also unpoison the loaded
4395 // reference, if heap poisoning is enabled).
4396 codegen_->MaybeGenerateReadBarrierSlow(
4397 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4398 }
4399 }
4400 break;
4401 }
4402
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004403 case Primitive::kPrimLong: {
4404 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004405 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004406 size_t offset =
4407 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004408 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004409 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004410 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004411 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004412 }
4413 break;
4414 }
4415
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004416 case Primitive::kPrimFloat: {
4417 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004418 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004419 if (index.IsConstant()) {
4420 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004421 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004422 } else {
4423 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00004424 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004425 }
4426 break;
4427 }
4428
4429 case Primitive::kPrimDouble: {
4430 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004431 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004432 if (index.IsConstant()) {
4433 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004434 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004435 } else {
4436 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004437 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004438 }
4439 break;
4440 }
4441
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004442 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004443 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004444 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004445 }
Roland Levillain4d027112015-07-01 15:41:14 +01004446
4447 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00004448 // Potential implicit null checks, in the case of reference
4449 // arrays, are handled in the previous switch statement.
4450 } else {
4451 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004452 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004453}
4454
4455void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004456 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004457
4458 bool needs_write_barrier =
4459 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004460 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4461 bool object_array_set_with_read_barrier =
4462 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004463
Nicolas Geoffray39468442014-09-02 15:17:15 +01004464 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004465 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004466 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4467 LocationSummary::kCallOnSlowPath :
4468 LocationSummary::kNoCall);
4469
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004470 locations->SetInAt(0, Location::RequiresRegister());
4471 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4472 if (Primitive::IsFloatingPointType(value_type)) {
4473 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004474 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004475 locations->SetInAt(2, Location::RequiresRegister());
4476 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004477 if (needs_write_barrier) {
4478 // Temporary registers for the write barrier.
4479 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004480 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004481 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004482}
4483
4484void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4485 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004486 Location array_loc = locations->InAt(0);
4487 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004488 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004489 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004490 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004491 bool needs_write_barrier =
4492 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004493
4494 switch (value_type) {
4495 case Primitive::kPrimBoolean:
4496 case Primitive::kPrimByte: {
4497 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004498 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004499 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004500 size_t offset =
4501 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004502 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004503 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004504 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004505 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4506 }
4507 break;
4508 }
4509
4510 case Primitive::kPrimShort:
4511 case Primitive::kPrimChar: {
4512 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004513 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004514 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004515 size_t offset =
4516 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004517 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004518 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004519 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004520 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4521 }
4522 break;
4523 }
4524
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004525 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004526 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004527 Location value_loc = locations->InAt(2);
4528 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004529 Register source = value;
4530
4531 if (instruction->InputAt(2)->IsNullConstant()) {
4532 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004533 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004534 size_t offset =
4535 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004536 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004537 } else {
4538 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004539 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004540 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004541 }
Roland Levillain1407ee72016-01-08 15:56:19 +00004542 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00004543 DCHECK(!needs_write_barrier);
4544 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004545 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004546 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004547
4548 DCHECK(needs_write_barrier);
4549 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4550 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4551 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4552 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4553 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4554 Label done;
4555 SlowPathCode* slow_path = nullptr;
4556
Roland Levillain3b359c72015-11-17 19:35:12 +00004557 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004558 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4559 codegen_->AddSlowPath(slow_path);
4560 if (instruction->GetValueCanBeNull()) {
4561 Label non_zero;
4562 __ CompareAndBranchIfNonZero(value, &non_zero);
4563 if (index.IsConstant()) {
4564 size_t offset =
4565 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4566 __ StoreToOffset(kStoreWord, value, array, offset);
4567 } else {
4568 DCHECK(index.IsRegister()) << index;
4569 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4570 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4571 }
4572 codegen_->MaybeRecordImplicitNullCheck(instruction);
4573 __ b(&done);
4574 __ Bind(&non_zero);
4575 }
4576
Roland Levillain3b359c72015-11-17 19:35:12 +00004577 if (kEmitCompilerReadBarrier) {
4578 // When read barriers are enabled, the type checking
4579 // instrumentation requires two read barriers:
4580 //
4581 // __ Mov(temp2, temp1);
4582 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4583 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004584 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004585 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4586 //
4587 // // /* HeapReference<Class> */ temp2 = value->klass_
4588 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004589 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004590 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4591 //
4592 // __ cmp(temp1, ShifterOperand(temp2));
4593 //
4594 // However, the second read barrier may trash `temp`, as it
4595 // is a temporary register, and as such would not be saved
4596 // along with live registers before calling the runtime (nor
4597 // restored afterwards). So in this case, we bail out and
4598 // delegate the work to the array set slow path.
4599 //
4600 // TODO: Extend the register allocator to support a new
4601 // "(locally) live temp" location so as to avoid always
4602 // going into the slow path when read barriers are enabled.
4603 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004604 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004605 // /* HeapReference<Class> */ temp1 = array->klass_
4606 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4607 codegen_->MaybeRecordImplicitNullCheck(instruction);
4608 __ MaybeUnpoisonHeapReference(temp1);
4609
4610 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4611 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4612 // /* HeapReference<Class> */ temp2 = value->klass_
4613 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4614 // If heap poisoning is enabled, no need to unpoison `temp1`
4615 // nor `temp2`, as we are comparing two poisoned references.
4616 __ cmp(temp1, ShifterOperand(temp2));
4617
4618 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4619 Label do_put;
4620 __ b(&do_put, EQ);
4621 // If heap poisoning is enabled, the `temp1` reference has
4622 // not been unpoisoned yet; unpoison it now.
4623 __ MaybeUnpoisonHeapReference(temp1);
4624
4625 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4626 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4627 // If heap poisoning is enabled, no need to unpoison
4628 // `temp1`, as we are comparing against null below.
4629 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4630 __ Bind(&do_put);
4631 } else {
4632 __ b(slow_path->GetEntryLabel(), NE);
4633 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004634 }
4635 }
4636
4637 if (kPoisonHeapReferences) {
4638 // Note that in the case where `value` is a null reference,
4639 // we do not enter this block, as a null reference does not
4640 // need poisoning.
4641 DCHECK_EQ(value_type, Primitive::kPrimNot);
4642 __ Mov(temp1, value);
4643 __ PoisonHeapReference(temp1);
4644 source = temp1;
4645 }
4646
4647 if (index.IsConstant()) {
4648 size_t offset =
4649 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4650 __ StoreToOffset(kStoreWord, source, array, offset);
4651 } else {
4652 DCHECK(index.IsRegister()) << index;
4653 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4654 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4655 }
4656
Roland Levillain3b359c72015-11-17 19:35:12 +00004657 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004658 codegen_->MaybeRecordImplicitNullCheck(instruction);
4659 }
4660
4661 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4662
4663 if (done.IsLinked()) {
4664 __ Bind(&done);
4665 }
4666
4667 if (slow_path != nullptr) {
4668 __ Bind(slow_path->GetExitLabel());
4669 }
4670
4671 break;
4672 }
4673
4674 case Primitive::kPrimInt: {
4675 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4676 Register value = locations->InAt(2).AsRegister<Register>();
4677 if (index.IsConstant()) {
4678 size_t offset =
4679 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4680 __ StoreToOffset(kStoreWord, value, array, offset);
4681 } else {
4682 DCHECK(index.IsRegister()) << index;
4683 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4684 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4685 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004686 break;
4687 }
4688
4689 case Primitive::kPrimLong: {
4690 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004691 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004692 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004693 size_t offset =
4694 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004695 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004696 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004697 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004698 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004699 }
4700 break;
4701 }
4702
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004703 case Primitive::kPrimFloat: {
4704 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4705 Location value = locations->InAt(2);
4706 DCHECK(value.IsFpuRegister());
4707 if (index.IsConstant()) {
4708 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004709 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004710 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004711 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004712 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4713 }
4714 break;
4715 }
4716
4717 case Primitive::kPrimDouble: {
4718 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4719 Location value = locations->InAt(2);
4720 DCHECK(value.IsFpuRegisterPair());
4721 if (index.IsConstant()) {
4722 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004723 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004724 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004725 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004726 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4727 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004728
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004729 break;
4730 }
4731
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004732 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004733 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004734 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004735 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004736
Roland Levillain80e67092016-01-08 16:04:55 +00004737 // Objects are handled in the switch.
4738 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004739 codegen_->MaybeRecordImplicitNullCheck(instruction);
4740 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004741}
4742
4743void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004744 LocationSummary* locations =
4745 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004746 locations->SetInAt(0, Location::RequiresRegister());
4747 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004748}
4749
4750void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4751 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01004752 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004753 Register obj = locations->InAt(0).AsRegister<Register>();
4754 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004755 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004756 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004757}
4758
4759void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004760 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4761 ? LocationSummary::kCallOnSlowPath
4762 : LocationSummary::kNoCall;
4763 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004764 locations->SetInAt(0, Location::RequiresRegister());
4765 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004766 if (instruction->HasUses()) {
4767 locations->SetOut(Location::SameAsFirstInput());
4768 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004769}
4770
4771void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4772 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004773 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004774 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004775 codegen_->AddSlowPath(slow_path);
4776
Roland Levillain271ab9c2014-11-27 15:23:57 +00004777 Register index = locations->InAt(0).AsRegister<Register>();
4778 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004779
4780 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004781 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004782}
4783
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004784void CodeGeneratorARM::MarkGCCard(Register temp,
4785 Register card,
4786 Register object,
4787 Register value,
4788 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004789 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004790 if (can_be_null) {
4791 __ CompareAndBranchIfZero(value, &is_null);
4792 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004793 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4794 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4795 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004796 if (can_be_null) {
4797 __ Bind(&is_null);
4798 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004799}
4800
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004801void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004802 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004803}
4804
4805void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004806 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4807}
4808
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004809void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4810 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4811}
4812
4813void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004814 HBasicBlock* block = instruction->GetBlock();
4815 if (block->GetLoopInformation() != nullptr) {
4816 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4817 // The back edge will generate the suspend check.
4818 return;
4819 }
4820 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4821 // The goto will generate the suspend check.
4822 return;
4823 }
4824 GenerateSuspendCheck(instruction, nullptr);
4825}
4826
4827void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4828 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004829 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004830 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4831 if (slow_path == nullptr) {
4832 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4833 instruction->SetSlowPath(slow_path);
4834 codegen_->AddSlowPath(slow_path);
4835 if (successor != nullptr) {
4836 DCHECK(successor->IsLoopHeader());
4837 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4838 }
4839 } else {
4840 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4841 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004842
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004843 __ LoadFromOffset(
4844 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004845 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004846 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004847 __ Bind(slow_path->GetReturnLabel());
4848 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004849 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004850 __ b(slow_path->GetEntryLabel());
4851 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004852}
4853
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004854ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4855 return codegen_->GetAssembler();
4856}
4857
4858void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004859 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004860 Location source = move->GetSource();
4861 Location destination = move->GetDestination();
4862
4863 if (source.IsRegister()) {
4864 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004865 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004866 } else if (destination.IsFpuRegister()) {
4867 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004868 } else {
4869 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004870 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004871 SP, destination.GetStackIndex());
4872 }
4873 } else if (source.IsStackSlot()) {
4874 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004875 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004876 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004877 } else if (destination.IsFpuRegister()) {
4878 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004879 } else {
4880 DCHECK(destination.IsStackSlot());
4881 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4882 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4883 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004884 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004885 if (destination.IsRegister()) {
4886 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
4887 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004888 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004889 } else {
4890 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004891 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4892 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004893 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004894 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004895 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4896 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004897 } else if (destination.IsRegisterPair()) {
4898 DCHECK(ExpectedPairLayout(destination));
4899 __ LoadFromOffset(
4900 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4901 } else {
4902 DCHECK(destination.IsFpuRegisterPair()) << destination;
4903 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4904 SP,
4905 source.GetStackIndex());
4906 }
4907 } else if (source.IsRegisterPair()) {
4908 if (destination.IsRegisterPair()) {
4909 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4910 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004911 } else if (destination.IsFpuRegisterPair()) {
4912 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4913 source.AsRegisterPairLow<Register>(),
4914 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004915 } else {
4916 DCHECK(destination.IsDoubleStackSlot()) << destination;
4917 DCHECK(ExpectedPairLayout(source));
4918 __ StoreToOffset(
4919 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4920 }
4921 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004922 if (destination.IsRegisterPair()) {
4923 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4924 destination.AsRegisterPairHigh<Register>(),
4925 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4926 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004927 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4928 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4929 } else {
4930 DCHECK(destination.IsDoubleStackSlot()) << destination;
4931 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4932 SP,
4933 destination.GetStackIndex());
4934 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004935 } else {
4936 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004937 HConstant* constant = source.GetConstant();
4938 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4939 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004940 if (destination.IsRegister()) {
4941 __ LoadImmediate(destination.AsRegister<Register>(), value);
4942 } else {
4943 DCHECK(destination.IsStackSlot());
4944 __ LoadImmediate(IP, value);
4945 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4946 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004947 } else if (constant->IsLongConstant()) {
4948 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004949 if (destination.IsRegisterPair()) {
4950 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4951 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004952 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004953 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004954 __ LoadImmediate(IP, Low32Bits(value));
4955 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4956 __ LoadImmediate(IP, High32Bits(value));
4957 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4958 }
4959 } else if (constant->IsDoubleConstant()) {
4960 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004961 if (destination.IsFpuRegisterPair()) {
4962 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004963 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004964 DCHECK(destination.IsDoubleStackSlot()) << destination;
4965 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004966 __ LoadImmediate(IP, Low32Bits(int_value));
4967 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4968 __ LoadImmediate(IP, High32Bits(int_value));
4969 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4970 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004971 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004972 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004973 float value = constant->AsFloatConstant()->GetValue();
4974 if (destination.IsFpuRegister()) {
4975 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4976 } else {
4977 DCHECK(destination.IsStackSlot());
4978 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4979 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4980 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004981 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004982 }
4983}
4984
4985void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4986 __ Mov(IP, reg);
4987 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4988 __ StoreToOffset(kStoreWord, IP, SP, mem);
4989}
4990
4991void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4992 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4993 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4994 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4995 SP, mem1 + stack_offset);
4996 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4997 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4998 SP, mem2 + stack_offset);
4999 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5000}
5001
5002void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005003 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005004 Location source = move->GetSource();
5005 Location destination = move->GetDestination();
5006
5007 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005008 DCHECK_NE(source.AsRegister<Register>(), IP);
5009 DCHECK_NE(destination.AsRegister<Register>(), IP);
5010 __ Mov(IP, source.AsRegister<Register>());
5011 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5012 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005013 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005014 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005015 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005016 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005017 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5018 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005019 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005020 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005021 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005022 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005023 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005024 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005025 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005026 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005027 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5028 destination.AsRegisterPairHigh<Register>(),
5029 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005030 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005031 Register low_reg = source.IsRegisterPair()
5032 ? source.AsRegisterPairLow<Register>()
5033 : destination.AsRegisterPairLow<Register>();
5034 int mem = source.IsRegisterPair()
5035 ? destination.GetStackIndex()
5036 : source.GetStackIndex();
5037 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005038 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005039 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005040 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005041 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005042 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5043 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005044 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005045 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005046 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005047 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5048 DRegister reg = source.IsFpuRegisterPair()
5049 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5050 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5051 int mem = source.IsFpuRegisterPair()
5052 ? destination.GetStackIndex()
5053 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005054 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005055 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005056 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005057 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5058 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5059 : destination.AsFpuRegister<SRegister>();
5060 int mem = source.IsFpuRegister()
5061 ? destination.GetStackIndex()
5062 : source.GetStackIndex();
5063
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005064 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005065 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005066 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005067 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005068 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5069 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005070 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005071 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005072 }
5073}
5074
5075void ParallelMoveResolverARM::SpillScratch(int reg) {
5076 __ Push(static_cast<Register>(reg));
5077}
5078
5079void ParallelMoveResolverARM::RestoreScratch(int reg) {
5080 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005081}
5082
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005083HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
5084 HLoadClass::LoadKind desired_class_load_kind) {
5085 if (kEmitCompilerReadBarrier) {
5086 switch (desired_class_load_kind) {
5087 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5088 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5089 case HLoadClass::LoadKind::kBootImageAddress:
5090 // TODO: Implement for read barrier.
5091 return HLoadClass::LoadKind::kDexCacheViaMethod;
5092 default:
5093 break;
5094 }
5095 }
5096 switch (desired_class_load_kind) {
5097 case HLoadClass::LoadKind::kReferrersClass:
5098 break;
5099 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5100 DCHECK(!GetCompilerOptions().GetCompilePic());
5101 break;
5102 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5103 DCHECK(GetCompilerOptions().GetCompilePic());
5104 break;
5105 case HLoadClass::LoadKind::kBootImageAddress:
5106 break;
5107 case HLoadClass::LoadKind::kDexCacheAddress:
5108 DCHECK(Runtime::Current()->UseJitCompilation());
5109 break;
5110 case HLoadClass::LoadKind::kDexCachePcRelative:
5111 DCHECK(!Runtime::Current()->UseJitCompilation());
5112 // We disable pc-relative load when there is an irreducible loop, as the optimization
5113 // is incompatible with it.
5114 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5115 // with irreducible loops.
5116 if (GetGraph()->HasIrreducibleLoops()) {
5117 return HLoadClass::LoadKind::kDexCacheViaMethod;
5118 }
5119 break;
5120 case HLoadClass::LoadKind::kDexCacheViaMethod:
5121 break;
5122 }
5123 return desired_class_load_kind;
5124}
5125
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005126void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005127 if (cls->NeedsAccessCheck()) {
5128 InvokeRuntimeCallingConvention calling_convention;
5129 CodeGenerator::CreateLoadClassLocationSummary(
5130 cls,
5131 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5132 Location::RegisterLocation(R0),
5133 /* code_generator_supports_read_barrier */ true);
5134 return;
5135 }
5136
5137 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
5138 ? LocationSummary::kCallOnSlowPath
5139 : LocationSummary::kNoCall;
5140 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
5141 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5142 if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
5143 load_kind == HLoadClass::LoadKind::kDexCacheViaMethod ||
5144 load_kind == HLoadClass::LoadKind::kDexCachePcRelative) {
5145 locations->SetInAt(0, Location::RequiresRegister());
5146 }
5147 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005148}
5149
5150void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005151 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005152 if (cls->NeedsAccessCheck()) {
5153 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5154 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5155 cls,
5156 cls->GetDexPc(),
5157 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005158 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005159 return;
5160 }
5161
Roland Levillain3b359c72015-11-17 19:35:12 +00005162 Location out_loc = locations->Out();
5163 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005164
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005165 bool generate_null_check = false;
5166 switch (cls->GetLoadKind()) {
5167 case HLoadClass::LoadKind::kReferrersClass: {
5168 DCHECK(!cls->CanCallRuntime());
5169 DCHECK(!cls->MustGenerateClinitCheck());
5170 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5171 Register current_method = locations->InAt(0).AsRegister<Register>();
5172 GenerateGcRootFieldLoad(
5173 cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5174 break;
5175 }
5176 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
5177 DCHECK(!kEmitCompilerReadBarrier);
5178 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5179 cls->GetTypeIndex()));
5180 break;
5181 }
5182 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5183 DCHECK(!kEmitCompilerReadBarrier);
5184 CodeGeneratorARM::PcRelativePatchInfo* labels =
5185 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5186 __ BindTrackedLabel(&labels->movw_label);
5187 __ movw(out, /* placeholder */ 0u);
5188 __ BindTrackedLabel(&labels->movt_label);
5189 __ movt(out, /* placeholder */ 0u);
5190 __ BindTrackedLabel(&labels->add_pc_label);
5191 __ add(out, out, ShifterOperand(PC));
5192 break;
5193 }
5194 case HLoadClass::LoadKind::kBootImageAddress: {
5195 DCHECK(!kEmitCompilerReadBarrier);
5196 DCHECK_NE(cls->GetAddress(), 0u);
5197 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5198 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5199 break;
5200 }
5201 case HLoadClass::LoadKind::kDexCacheAddress: {
5202 DCHECK_NE(cls->GetAddress(), 0u);
5203 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
5204 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5205 // a 128B range. To try and reduce the number of literals if we load multiple types,
5206 // simply split the dex cache address to a 128B aligned base loaded from a literal
5207 // and the remaining offset embedded in the load.
5208 static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
5209 DCHECK_ALIGNED(cls->GetAddress(), 4u);
5210 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5211 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5212 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5213 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5214 // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
5215 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5216 generate_null_check = !cls->IsInDexCache();
5217 break;
5218 }
5219 case HLoadClass::LoadKind::kDexCachePcRelative: {
5220 Register base_reg = locations->InAt(0).AsRegister<Register>();
5221 HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase();
5222 int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset();
5223 // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
5224 GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset);
5225 generate_null_check = !cls->IsInDexCache();
5226 break;
5227 }
5228 case HLoadClass::LoadKind::kDexCacheViaMethod: {
5229 // /* GcRoot<mirror::Class>[] */ out =
5230 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
5231 Register current_method = locations->InAt(0).AsRegister<Register>();
5232 __ LoadFromOffset(kLoadWord,
5233 out,
5234 current_method,
5235 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
5236 // /* GcRoot<mirror::Class> */ out = out[type_index]
5237 size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
5238 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
5239 generate_null_check = !cls->IsInDexCache();
5240 }
5241 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005242
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005243 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5244 DCHECK(cls->CanCallRuntime());
5245 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5246 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5247 codegen_->AddSlowPath(slow_path);
5248 if (generate_null_check) {
5249 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5250 }
5251 if (cls->MustGenerateClinitCheck()) {
5252 GenerateClassInitializationCheck(slow_path, out);
5253 } else {
5254 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005255 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005256 }
5257}
5258
5259void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5260 LocationSummary* locations =
5261 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5262 locations->SetInAt(0, Location::RequiresRegister());
5263 if (check->HasUses()) {
5264 locations->SetOut(Location::SameAsFirstInput());
5265 }
5266}
5267
5268void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005269 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005270 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005271 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005272 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005273 GenerateClassInitializationCheck(slow_path,
5274 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005275}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005276
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005277void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005278 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005279 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5280 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5281 __ b(slow_path->GetEntryLabel(), LT);
5282 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5283 // properly. Therefore, we do a memory fence.
5284 __ dmb(ISH);
5285 __ Bind(slow_path->GetExitLabel());
5286}
5287
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005288HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5289 HLoadString::LoadKind desired_string_load_kind) {
5290 if (kEmitCompilerReadBarrier) {
5291 switch (desired_string_load_kind) {
5292 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5293 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5294 case HLoadString::LoadKind::kBootImageAddress:
5295 // TODO: Implement for read barrier.
5296 return HLoadString::LoadKind::kDexCacheViaMethod;
5297 default:
5298 break;
5299 }
5300 }
5301 switch (desired_string_load_kind) {
5302 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5303 DCHECK(!GetCompilerOptions().GetCompilePic());
5304 break;
5305 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5306 DCHECK(GetCompilerOptions().GetCompilePic());
5307 break;
5308 case HLoadString::LoadKind::kBootImageAddress:
5309 break;
5310 case HLoadString::LoadKind::kDexCacheAddress:
Calin Juravleffc87072016-04-20 14:22:09 +01005311 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005312 break;
5313 case HLoadString::LoadKind::kDexCachePcRelative:
Calin Juravleffc87072016-04-20 14:22:09 +01005314 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005315 // We disable pc-relative load when there is an irreducible loop, as the optimization
5316 // is incompatible with it.
5317 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5318 // with irreducible loops.
5319 if (GetGraph()->HasIrreducibleLoops()) {
5320 return HLoadString::LoadKind::kDexCacheViaMethod;
5321 }
5322 break;
5323 case HLoadString::LoadKind::kDexCacheViaMethod:
5324 break;
5325 }
5326 return desired_string_load_kind;
5327}
5328
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005329void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005330 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005331 ? LocationSummary::kCallOnSlowPath
5332 : LocationSummary::kNoCall;
5333 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005334 HLoadString::LoadKind load_kind = load->GetLoadKind();
5335 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5336 load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5337 locations->SetInAt(0, Location::RequiresRegister());
5338 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005339 locations->SetOut(Location::RequiresRegister());
5340}
5341
5342void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005343 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005344 Location out_loc = locations->Out();
5345 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005346
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005347 switch (load->GetLoadKind()) {
5348 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5349 DCHECK(!kEmitCompilerReadBarrier);
5350 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5351 load->GetStringIndex()));
5352 return; // No dex cache slow path.
5353 }
5354 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5355 DCHECK(!kEmitCompilerReadBarrier);
5356 CodeGeneratorARM::PcRelativePatchInfo* labels =
5357 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5358 __ BindTrackedLabel(&labels->movw_label);
5359 __ movw(out, /* placeholder */ 0u);
5360 __ BindTrackedLabel(&labels->movt_label);
5361 __ movt(out, /* placeholder */ 0u);
5362 __ BindTrackedLabel(&labels->add_pc_label);
5363 __ add(out, out, ShifterOperand(PC));
5364 return; // No dex cache slow path.
5365 }
5366 case HLoadString::LoadKind::kBootImageAddress: {
5367 DCHECK(!kEmitCompilerReadBarrier);
5368 DCHECK_NE(load->GetAddress(), 0u);
5369 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5370 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5371 return; // No dex cache slow path.
5372 }
5373 case HLoadString::LoadKind::kDexCacheAddress: {
5374 DCHECK_NE(load->GetAddress(), 0u);
5375 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5376 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5377 // a 128B range. To try and reduce the number of literals if we load multiple strings,
5378 // simply split the dex cache address to a 128B aligned base loaded from a literal
5379 // and the remaining offset embedded in the load.
5380 static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5381 DCHECK_ALIGNED(load->GetAddress(), 4u);
5382 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5383 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5384 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5385 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005386 // /* GcRoot<mirror::String> */ out = *(base_address + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005387 GenerateGcRootFieldLoad(load, out_loc, out, offset);
5388 break;
5389 }
5390 case HLoadString::LoadKind::kDexCachePcRelative: {
5391 Register base_reg = locations->InAt(0).AsRegister<Register>();
5392 HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5393 int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005394 // /* GcRoot<mirror::String> */ out = *(dex_cache_arrays_base + offset)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005395 GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5396 break;
5397 }
5398 case HLoadString::LoadKind::kDexCacheViaMethod: {
5399 Register current_method = locations->InAt(0).AsRegister<Register>();
5400
5401 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5402 GenerateGcRootFieldLoad(
5403 load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5404 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5405 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5406 // /* GcRoot<mirror::String> */ out = out[string_index]
5407 GenerateGcRootFieldLoad(
5408 load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5409 break;
5410 }
5411 default:
5412 LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5413 UNREACHABLE();
5414 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005415
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005416 if (!load->IsInDexCache()) {
5417 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5418 codegen_->AddSlowPath(slow_path);
5419 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5420 __ Bind(slow_path->GetExitLabel());
5421 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005422}
5423
David Brazdilcb1c0552015-08-04 16:22:25 +01005424static int32_t GetExceptionTlsOffset() {
5425 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5426}
5427
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005428void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5429 LocationSummary* locations =
5430 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5431 locations->SetOut(Location::RequiresRegister());
5432}
5433
5434void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005435 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005436 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5437}
5438
5439void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5440 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5441}
5442
5443void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005444 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005445 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005446}
5447
5448void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5449 LocationSummary* locations =
5450 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5451 InvokeRuntimeCallingConvention calling_convention;
5452 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5453}
5454
5455void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5456 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005457 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005458 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005459}
5460
Roland Levillainc9285912015-12-18 10:38:42 +00005461static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5462 return kEmitCompilerReadBarrier &&
5463 (kUseBakerReadBarrier ||
5464 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5465 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5466 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5467}
5468
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005469void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005470 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005471 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5472 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005473 case TypeCheckKind::kExactCheck:
5474 case TypeCheckKind::kAbstractClassCheck:
5475 case TypeCheckKind::kClassHierarchyCheck:
5476 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005477 call_kind =
5478 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005479 break;
5480 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005481 case TypeCheckKind::kUnresolvedCheck:
5482 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005483 call_kind = LocationSummary::kCallOnSlowPath;
5484 break;
5485 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005486
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005487 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005488 locations->SetInAt(0, Location::RequiresRegister());
5489 locations->SetInAt(1, Location::RequiresRegister());
5490 // The "out" register is used as a temporary, so it overlaps with the inputs.
5491 // Note that TypeCheckSlowPathARM uses this register too.
5492 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5493 // When read barriers are enabled, we need a temporary register for
5494 // some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005495 if (TypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005496 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005497 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005498}
5499
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005500void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005501 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005502 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005503 Location obj_loc = locations->InAt(0);
5504 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005505 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005506 Location out_loc = locations->Out();
5507 Register out = out_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005508 Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005509 locations->GetTemp(0) :
5510 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005511 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005512 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5513 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5514 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005515 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005516 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005517
5518 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005519 // avoid null check if we know obj is not null.
5520 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005521 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005522 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005523
Roland Levillain3b359c72015-11-17 19:35:12 +00005524 // /* HeapReference<Class> */ out = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005525 GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005526
Roland Levillainc9285912015-12-18 10:38:42 +00005527 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005528 case TypeCheckKind::kExactCheck: {
5529 __ cmp(out, ShifterOperand(cls));
5530 // Classes must be equal for the instanceof to succeed.
5531 __ b(&zero, NE);
5532 __ LoadImmediate(out, 1);
5533 __ b(&done);
5534 break;
5535 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005536
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005537 case TypeCheckKind::kAbstractClassCheck: {
5538 // If the class is abstract, we eagerly fetch the super class of the
5539 // object to avoid doing a comparison we know will fail.
5540 Label loop;
5541 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005542 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005543 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005544 // If `out` is null, we use it for the result, and jump to `done`.
5545 __ CompareAndBranchIfZero(out, &done);
5546 __ cmp(out, ShifterOperand(cls));
5547 __ b(&loop, NE);
5548 __ LoadImmediate(out, 1);
5549 if (zero.IsLinked()) {
5550 __ b(&done);
5551 }
5552 break;
5553 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005554
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005555 case TypeCheckKind::kClassHierarchyCheck: {
5556 // Walk over the class hierarchy to find a match.
5557 Label loop, success;
5558 __ Bind(&loop);
5559 __ cmp(out, ShifterOperand(cls));
5560 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005561 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005562 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005563 __ CompareAndBranchIfNonZero(out, &loop);
5564 // If `out` is null, we use it for the result, and jump to `done`.
5565 __ b(&done);
5566 __ Bind(&success);
5567 __ LoadImmediate(out, 1);
5568 if (zero.IsLinked()) {
5569 __ b(&done);
5570 }
5571 break;
5572 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005573
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005574 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005575 // Do an exact check.
5576 Label exact_check;
5577 __ cmp(out, ShifterOperand(cls));
5578 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005579 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005580 // /* HeapReference<Class> */ out = out->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005581 GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005582 // If `out` is null, we use it for the result, and jump to `done`.
5583 __ CompareAndBranchIfZero(out, &done);
5584 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5585 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5586 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005587 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005588 __ LoadImmediate(out, 1);
5589 __ b(&done);
5590 break;
5591 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005592
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005593 case TypeCheckKind::kArrayCheck: {
5594 __ cmp(out, ShifterOperand(cls));
5595 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005596 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5597 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005598 codegen_->AddSlowPath(slow_path);
5599 __ b(slow_path->GetEntryLabel(), NE);
5600 __ LoadImmediate(out, 1);
5601 if (zero.IsLinked()) {
5602 __ b(&done);
5603 }
5604 break;
5605 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005606
Calin Juravle98893e12015-10-02 21:05:03 +01005607 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005608 case TypeCheckKind::kInterfaceCheck: {
5609 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005610 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00005611 // cases.
5612 //
5613 // We cannot directly call the InstanceofNonTrivial runtime
5614 // entry point without resorting to a type checking slow path
5615 // here (i.e. by calling InvokeRuntime directly), as it would
5616 // require to assign fixed registers for the inputs of this
5617 // HInstanceOf instruction (following the runtime calling
5618 // convention), which might be cluttered by the potential first
5619 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005620 //
5621 // TODO: Introduce a new runtime entry point taking the object
5622 // to test (instead of its class) as argument, and let it deal
5623 // with the read barrier issues. This will let us refactor this
5624 // case of the `switch` code as it was previously (with a direct
5625 // call to the runtime not using a type checking slow path).
5626 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005627 DCHECK(locations->OnlyCallsOnSlowPath());
5628 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5629 /* is_fatal */ false);
5630 codegen_->AddSlowPath(slow_path);
5631 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005632 if (zero.IsLinked()) {
5633 __ b(&done);
5634 }
5635 break;
5636 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005637 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005638
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005639 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005640 __ Bind(&zero);
5641 __ LoadImmediate(out, 0);
5642 }
5643
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005644 if (done.IsLinked()) {
5645 __ Bind(&done);
5646 }
5647
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005648 if (slow_path != nullptr) {
5649 __ Bind(slow_path->GetExitLabel());
5650 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005651}
5652
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005653void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005654 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5655 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5656
Roland Levillain3b359c72015-11-17 19:35:12 +00005657 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5658 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005659 case TypeCheckKind::kExactCheck:
5660 case TypeCheckKind::kAbstractClassCheck:
5661 case TypeCheckKind::kClassHierarchyCheck:
5662 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005663 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5664 LocationSummary::kCallOnSlowPath :
5665 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005666 break;
5667 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005668 case TypeCheckKind::kUnresolvedCheck:
5669 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005670 call_kind = LocationSummary::kCallOnSlowPath;
5671 break;
5672 }
5673
Roland Levillain3b359c72015-11-17 19:35:12 +00005674 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5675 locations->SetInAt(0, Location::RequiresRegister());
5676 locations->SetInAt(1, Location::RequiresRegister());
5677 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5678 locations->AddTemp(Location::RequiresRegister());
5679 // When read barriers are enabled, we need an additional temporary
5680 // register for some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005681 if (TypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005682 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005683 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005684}
5685
5686void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005687 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005688 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005689 Location obj_loc = locations->InAt(0);
5690 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005691 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005692 Location temp_loc = locations->GetTemp(0);
5693 Register temp = temp_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005694 Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005695 locations->GetTemp(1) :
5696 Location::NoLocation();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005697 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005698 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5699 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5700 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005701
Roland Levillain3b359c72015-11-17 19:35:12 +00005702 bool is_type_check_slow_path_fatal =
5703 (type_check_kind == TypeCheckKind::kExactCheck ||
5704 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5705 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5706 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5707 !instruction->CanThrowIntoCatchBlock();
5708 SlowPathCode* type_check_slow_path =
5709 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5710 is_type_check_slow_path_fatal);
5711 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005712
5713 Label done;
5714 // Avoid null check if we know obj is not null.
5715 if (instruction->MustDoNullCheck()) {
5716 __ CompareAndBranchIfZero(obj, &done);
5717 }
5718
Roland Levillain3b359c72015-11-17 19:35:12 +00005719 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005720 GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005721
Roland Levillain3b359c72015-11-17 19:35:12 +00005722 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005723 case TypeCheckKind::kExactCheck:
5724 case TypeCheckKind::kArrayCheck: {
5725 __ cmp(temp, ShifterOperand(cls));
5726 // Jump to slow path for throwing the exception or doing a
5727 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005728 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005729 break;
5730 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005731
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005732 case TypeCheckKind::kAbstractClassCheck: {
5733 // If the class is abstract, we eagerly fetch the super class of the
5734 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005735 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005736 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005737 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005738 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005739
5740 // If the class reference currently in `temp` is not null, jump
5741 // to the `compare_classes` label to compare it with the checked
5742 // class.
5743 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5744 // Otherwise, jump to the slow path to throw the exception.
5745 //
5746 // But before, move back the object's class into `temp` before
5747 // going into the slow path, as it has been overwritten in the
5748 // meantime.
5749 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005750 GenerateReferenceLoadTwoRegisters(
5751 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005752 __ b(type_check_slow_path->GetEntryLabel());
5753
5754 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005755 __ cmp(temp, ShifterOperand(cls));
5756 __ b(&loop, NE);
5757 break;
5758 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005759
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005760 case TypeCheckKind::kClassHierarchyCheck: {
5761 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005762 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005763 __ Bind(&loop);
5764 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005765 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005766
Roland Levillain3b359c72015-11-17 19:35:12 +00005767 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005768 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005769
5770 // If the class reference currently in `temp` is not null, jump
5771 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005772 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005773 // Otherwise, jump to the slow path to throw the exception.
5774 //
5775 // But before, move back the object's class into `temp` before
5776 // going into the slow path, as it has been overwritten in the
5777 // meantime.
5778 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005779 GenerateReferenceLoadTwoRegisters(
5780 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005781 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005782 break;
5783 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005784
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005785 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005786 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005787 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005788 __ cmp(temp, ShifterOperand(cls));
5789 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005790
5791 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005792 // /* HeapReference<Class> */ temp = temp->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005793 GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005794
5795 // If the component type is not null (i.e. the object is indeed
5796 // an array), jump to label `check_non_primitive_component_type`
5797 // to further check that this component type is not a primitive
5798 // type.
5799 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5800 // Otherwise, jump to the slow path to throw the exception.
5801 //
5802 // But before, move back the object's class into `temp` before
5803 // going into the slow path, as it has been overwritten in the
5804 // meantime.
5805 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005806 GenerateReferenceLoadTwoRegisters(
5807 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005808 __ b(type_check_slow_path->GetEntryLabel());
5809
5810 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005811 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005812 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5813 __ CompareAndBranchIfZero(temp, &done);
5814 // Same comment as above regarding `temp` and the slow path.
5815 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005816 GenerateReferenceLoadTwoRegisters(
5817 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005818 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005819 break;
5820 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005821
Calin Juravle98893e12015-10-02 21:05:03 +01005822 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005823 case TypeCheckKind::kInterfaceCheck:
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005824 // We always go into the type check slow path for the unresolved
5825 // and interface check cases.
Roland Levillain3b359c72015-11-17 19:35:12 +00005826 //
5827 // We cannot directly call the CheckCast runtime entry point
5828 // without resorting to a type checking slow path here (i.e. by
5829 // calling InvokeRuntime directly), as it would require to
5830 // assign fixed registers for the inputs of this HInstanceOf
5831 // instruction (following the runtime calling convention), which
5832 // might be cluttered by the potential first read barrier
5833 // emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005834 //
5835 // TODO: Introduce a new runtime entry point taking the object
5836 // to test (instead of its class) as argument, and let it deal
5837 // with the read barrier issues. This will let us refactor this
5838 // case of the `switch` code as it was previously (with a direct
5839 // call to the runtime not using a type checking slow path).
5840 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005841 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005842 break;
5843 }
5844 __ Bind(&done);
5845
Roland Levillain3b359c72015-11-17 19:35:12 +00005846 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005847}
5848
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005849void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5850 LocationSummary* locations =
5851 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5852 InvokeRuntimeCallingConvention calling_convention;
5853 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5854}
5855
5856void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5857 codegen_->InvokeRuntime(instruction->IsEnter()
5858 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5859 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005860 instruction->GetDexPc(),
5861 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005862 if (instruction->IsEnter()) {
5863 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5864 } else {
5865 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5866 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005867}
5868
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005869void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5870void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5871void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005872
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005873void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005874 LocationSummary* locations =
5875 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5876 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5877 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005878 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005879 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005880 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005881 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005882}
5883
5884void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5885 HandleBitwiseOperation(instruction);
5886}
5887
5888void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5889 HandleBitwiseOperation(instruction);
5890}
5891
5892void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5893 HandleBitwiseOperation(instruction);
5894}
5895
Artem Serov7fc63502016-02-09 17:15:29 +00005896
5897void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5898 LocationSummary* locations =
5899 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5900 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5901 || instruction->GetResultType() == Primitive::kPrimLong);
5902
5903 locations->SetInAt(0, Location::RequiresRegister());
5904 locations->SetInAt(1, Location::RequiresRegister());
5905 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5906}
5907
5908void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5909 LocationSummary* locations = instruction->GetLocations();
5910 Location first = locations->InAt(0);
5911 Location second = locations->InAt(1);
5912 Location out = locations->Out();
5913
5914 if (instruction->GetResultType() == Primitive::kPrimInt) {
5915 Register first_reg = first.AsRegister<Register>();
5916 ShifterOperand second_reg(second.AsRegister<Register>());
5917 Register out_reg = out.AsRegister<Register>();
5918
5919 switch (instruction->GetOpKind()) {
5920 case HInstruction::kAnd:
5921 __ bic(out_reg, first_reg, second_reg);
5922 break;
5923 case HInstruction::kOr:
5924 __ orn(out_reg, first_reg, second_reg);
5925 break;
5926 // There is no EON on arm.
5927 case HInstruction::kXor:
5928 default:
5929 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5930 UNREACHABLE();
5931 }
5932 return;
5933
5934 } else {
5935 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5936 Register first_low = first.AsRegisterPairLow<Register>();
5937 Register first_high = first.AsRegisterPairHigh<Register>();
5938 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5939 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5940 Register out_low = out.AsRegisterPairLow<Register>();
5941 Register out_high = out.AsRegisterPairHigh<Register>();
5942
5943 switch (instruction->GetOpKind()) {
5944 case HInstruction::kAnd:
5945 __ bic(out_low, first_low, second_low);
5946 __ bic(out_high, first_high, second_high);
5947 break;
5948 case HInstruction::kOr:
5949 __ orn(out_low, first_low, second_low);
5950 __ orn(out_high, first_high, second_high);
5951 break;
5952 // There is no EON on arm.
5953 case HInstruction::kXor:
5954 default:
5955 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5956 UNREACHABLE();
5957 }
5958 }
5959}
5960
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005961void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5962 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5963 if (value == 0xffffffffu) {
5964 if (out != first) {
5965 __ mov(out, ShifterOperand(first));
5966 }
5967 return;
5968 }
5969 if (value == 0u) {
5970 __ mov(out, ShifterOperand(0));
5971 return;
5972 }
5973 ShifterOperand so;
5974 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5975 __ and_(out, first, so);
5976 } else {
5977 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5978 __ bic(out, first, ShifterOperand(~value));
5979 }
5980}
5981
5982void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5983 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5984 if (value == 0u) {
5985 if (out != first) {
5986 __ mov(out, ShifterOperand(first));
5987 }
5988 return;
5989 }
5990 if (value == 0xffffffffu) {
5991 __ mvn(out, ShifterOperand(0));
5992 return;
5993 }
5994 ShifterOperand so;
5995 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5996 __ orr(out, first, so);
5997 } else {
5998 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5999 __ orn(out, first, ShifterOperand(~value));
6000 }
6001}
6002
6003void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
6004 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
6005 if (value == 0u) {
6006 if (out != first) {
6007 __ mov(out, ShifterOperand(first));
6008 }
6009 return;
6010 }
6011 __ eor(out, first, ShifterOperand(value));
6012}
6013
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006014void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
6015 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006016 Location first = locations->InAt(0);
6017 Location second = locations->InAt(1);
6018 Location out = locations->Out();
6019
6020 if (second.IsConstant()) {
6021 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
6022 uint32_t value_low = Low32Bits(value);
6023 if (instruction->GetResultType() == Primitive::kPrimInt) {
6024 Register first_reg = first.AsRegister<Register>();
6025 Register out_reg = out.AsRegister<Register>();
6026 if (instruction->IsAnd()) {
6027 GenerateAndConst(out_reg, first_reg, value_low);
6028 } else if (instruction->IsOr()) {
6029 GenerateOrrConst(out_reg, first_reg, value_low);
6030 } else {
6031 DCHECK(instruction->IsXor());
6032 GenerateEorConst(out_reg, first_reg, value_low);
6033 }
6034 } else {
6035 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
6036 uint32_t value_high = High32Bits(value);
6037 Register first_low = first.AsRegisterPairLow<Register>();
6038 Register first_high = first.AsRegisterPairHigh<Register>();
6039 Register out_low = out.AsRegisterPairLow<Register>();
6040 Register out_high = out.AsRegisterPairHigh<Register>();
6041 if (instruction->IsAnd()) {
6042 GenerateAndConst(out_low, first_low, value_low);
6043 GenerateAndConst(out_high, first_high, value_high);
6044 } else if (instruction->IsOr()) {
6045 GenerateOrrConst(out_low, first_low, value_low);
6046 GenerateOrrConst(out_high, first_high, value_high);
6047 } else {
6048 DCHECK(instruction->IsXor());
6049 GenerateEorConst(out_low, first_low, value_low);
6050 GenerateEorConst(out_high, first_high, value_high);
6051 }
6052 }
6053 return;
6054 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006055
6056 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006057 Register first_reg = first.AsRegister<Register>();
6058 ShifterOperand second_reg(second.AsRegister<Register>());
6059 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006060 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006061 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006062 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006063 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006064 } else {
6065 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006066 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006067 }
6068 } else {
6069 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006070 Register first_low = first.AsRegisterPairLow<Register>();
6071 Register first_high = first.AsRegisterPairHigh<Register>();
6072 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6073 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6074 Register out_low = out.AsRegisterPairLow<Register>();
6075 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006076 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006077 __ and_(out_low, first_low, second_low);
6078 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006079 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006080 __ orr(out_low, first_low, second_low);
6081 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006082 } else {
6083 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006084 __ eor(out_low, first_low, second_low);
6085 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006086 }
6087 }
6088}
6089
Roland Levillainc9285912015-12-18 10:38:42 +00006090void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
6091 Location out,
6092 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006093 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006094 Register out_reg = out.AsRegister<Register>();
6095 if (kEmitCompilerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006096 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006097 if (kUseBakerReadBarrier) {
6098 // Load with fast path based Baker's read barrier.
6099 // /* HeapReference<Object> */ out = *(out + offset)
6100 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006101 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006102 } else {
6103 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006104 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006105 // in the following move operation, as we will need it for the
6106 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006107 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006108 // /* HeapReference<Object> */ out = *(out + offset)
6109 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006110 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006111 }
6112 } else {
6113 // Plain load with no read barrier.
6114 // /* HeapReference<Object> */ out = *(out + offset)
6115 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6116 __ MaybeUnpoisonHeapReference(out_reg);
6117 }
6118}
6119
6120void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6121 Location out,
6122 Location obj,
6123 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006124 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006125 Register out_reg = out.AsRegister<Register>();
6126 Register obj_reg = obj.AsRegister<Register>();
6127 if (kEmitCompilerReadBarrier) {
6128 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006129 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006130 // Load with fast path based Baker's read barrier.
6131 // /* HeapReference<Object> */ out = *(obj + offset)
6132 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006133 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006134 } else {
6135 // Load with slow path based read barrier.
6136 // /* HeapReference<Object> */ out = *(obj + offset)
6137 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6138 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6139 }
6140 } else {
6141 // Plain load with no read barrier.
6142 // /* HeapReference<Object> */ out = *(obj + offset)
6143 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6144 __ MaybeUnpoisonHeapReference(out_reg);
6145 }
6146}
6147
6148void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6149 Location root,
6150 Register obj,
6151 uint32_t offset) {
6152 Register root_reg = root.AsRegister<Register>();
6153 if (kEmitCompilerReadBarrier) {
6154 if (kUseBakerReadBarrier) {
6155 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6156 // Baker's read barrier are used:
6157 //
6158 // root = obj.field;
6159 // if (Thread::Current()->GetIsGcMarking()) {
6160 // root = ReadBarrier::Mark(root)
6161 // }
6162
6163 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6164 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6165 static_assert(
6166 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6167 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6168 "have different sizes.");
6169 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6170 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6171 "have different sizes.");
6172
6173 // Slow path used to mark the GC root `root`.
6174 SlowPathCode* slow_path =
6175 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
6176 codegen_->AddSlowPath(slow_path);
6177
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006178 // IP = Thread::Current()->GetIsGcMarking()
Roland Levillainc9285912015-12-18 10:38:42 +00006179 __ LoadFromOffset(
6180 kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6181 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6182 __ Bind(slow_path->GetExitLabel());
6183 } else {
6184 // GC root loaded through a slow path for read barriers other
6185 // than Baker's.
6186 // /* GcRoot<mirror::Object>* */ root = obj + offset
6187 __ AddConstant(root_reg, obj, offset);
6188 // /* mirror::Object* */ root = root->Read()
6189 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6190 }
6191 } else {
6192 // Plain GC root load with no read barrier.
6193 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6194 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6195 // Note that GC roots are not affected by heap poisoning, thus we
6196 // do not have to unpoison `root_reg` here.
6197 }
6198}
6199
6200void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6201 Location ref,
6202 Register obj,
6203 uint32_t offset,
6204 Location temp,
6205 bool needs_null_check) {
6206 DCHECK(kEmitCompilerReadBarrier);
6207 DCHECK(kUseBakerReadBarrier);
6208
6209 // /* HeapReference<Object> */ ref = *(obj + offset)
6210 Location no_index = Location::NoLocation();
6211 GenerateReferenceLoadWithBakerReadBarrier(
6212 instruction, ref, obj, offset, no_index, temp, needs_null_check);
6213}
6214
6215void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6216 Location ref,
6217 Register obj,
6218 uint32_t data_offset,
6219 Location index,
6220 Location temp,
6221 bool needs_null_check) {
6222 DCHECK(kEmitCompilerReadBarrier);
6223 DCHECK(kUseBakerReadBarrier);
6224
6225 // /* HeapReference<Object> */ ref =
6226 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
6227 GenerateReferenceLoadWithBakerReadBarrier(
6228 instruction, ref, obj, data_offset, index, temp, needs_null_check);
6229}
6230
6231void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6232 Location ref,
6233 Register obj,
6234 uint32_t offset,
6235 Location index,
6236 Location temp,
6237 bool needs_null_check) {
6238 DCHECK(kEmitCompilerReadBarrier);
6239 DCHECK(kUseBakerReadBarrier);
6240
6241 // In slow path based read barriers, the read barrier call is
6242 // inserted after the original load. However, in fast path based
6243 // Baker's read barriers, we need to perform the load of
6244 // mirror::Object::monitor_ *before* the original reference load.
6245 // This load-load ordering is required by the read barrier.
6246 // The fast path/slow path (for Baker's algorithm) should look like:
6247 //
6248 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6249 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6250 // HeapReference<Object> ref = *src; // Original reference load.
6251 // bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6252 // if (is_gray) {
6253 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6254 // }
6255 //
6256 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006257 // slightly more complex as it performs additional checks that we do
6258 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00006259
6260 Register ref_reg = ref.AsRegister<Register>();
6261 Register temp_reg = temp.AsRegister<Register>();
6262 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6263
6264 // /* int32_t */ monitor = obj->monitor_
6265 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6266 if (needs_null_check) {
6267 MaybeRecordImplicitNullCheck(instruction);
6268 }
6269 // /* LockWord */ lock_word = LockWord(monitor)
6270 static_assert(sizeof(LockWord) == sizeof(int32_t),
6271 "art::LockWord and int32_t have different sizes.");
6272 // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
6273 __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
6274 __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6275 static_assert(
6276 LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
6277 "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
6278
6279 // Introduce a dependency on the high bits of rb_state, which shall
6280 // be all zeroes, to prevent load-load reordering, and without using
6281 // a memory barrier (which would be more expensive).
6282 // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
6283 __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6284 // obj is unchanged by this operation, but its value now depends on
6285 // IP, which depends on temp_reg.
6286 __ add(obj, obj, ShifterOperand(IP));
6287
6288 // The actual reference load.
6289 if (index.IsValid()) {
6290 static_assert(
6291 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6292 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6293 // /* HeapReference<Object> */ ref =
6294 // *(obj + offset + index * sizeof(HeapReference<Object>))
6295 if (index.IsConstant()) {
6296 size_t computed_offset =
6297 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
6298 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6299 } else {
6300 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
6301 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6302 }
6303 } else {
6304 // /* HeapReference<Object> */ ref = *(obj + offset)
6305 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6306 }
6307
6308 // Object* ref = ref_addr->AsMirrorPtr()
6309 __ MaybeUnpoisonHeapReference(ref_reg);
6310
6311 // Slow path used to mark the object `ref` when it is gray.
6312 SlowPathCode* slow_path =
6313 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
6314 AddSlowPath(slow_path);
6315
6316 // if (rb_state == ReadBarrier::gray_ptr_)
6317 // ref = ReadBarrier::Mark(ref);
6318 __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
6319 __ b(slow_path->GetEntryLabel(), EQ);
6320 __ Bind(slow_path->GetExitLabel());
6321}
6322
6323void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6324 Location out,
6325 Location ref,
6326 Location obj,
6327 uint32_t offset,
6328 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006329 DCHECK(kEmitCompilerReadBarrier);
6330
Roland Levillainc9285912015-12-18 10:38:42 +00006331 // Insert a slow path based read barrier *after* the reference load.
6332 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006333 // If heap poisoning is enabled, the unpoisoning of the loaded
6334 // reference will be carried out by the runtime within the slow
6335 // path.
6336 //
6337 // Note that `ref` currently does not get unpoisoned (when heap
6338 // poisoning is enabled), which is alright as the `ref` argument is
6339 // not used by the artReadBarrierSlow entry point.
6340 //
6341 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6342 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6343 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6344 AddSlowPath(slow_path);
6345
Roland Levillain3b359c72015-11-17 19:35:12 +00006346 __ b(slow_path->GetEntryLabel());
6347 __ Bind(slow_path->GetExitLabel());
6348}
6349
Roland Levillainc9285912015-12-18 10:38:42 +00006350void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6351 Location out,
6352 Location ref,
6353 Location obj,
6354 uint32_t offset,
6355 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006356 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00006357 // Baker's read barriers shall be handled by the fast path
6358 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6359 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006360 // If heap poisoning is enabled, unpoisoning will be taken care of
6361 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00006362 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00006363 } else if (kPoisonHeapReferences) {
6364 __ UnpoisonHeapReference(out.AsRegister<Register>());
6365 }
6366}
6367
Roland Levillainc9285912015-12-18 10:38:42 +00006368void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6369 Location out,
6370 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006371 DCHECK(kEmitCompilerReadBarrier);
6372
Roland Levillainc9285912015-12-18 10:38:42 +00006373 // Insert a slow path based read barrier *after* the GC root load.
6374 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006375 // Note that GC roots are not affected by heap poisoning, so we do
6376 // not need to do anything special for this here.
6377 SlowPathCode* slow_path =
6378 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6379 AddSlowPath(slow_path);
6380
Roland Levillain3b359c72015-11-17 19:35:12 +00006381 __ b(slow_path->GetEntryLabel());
6382 __ Bind(slow_path->GetExitLabel());
6383}
6384
Vladimir Markodc151b22015-10-15 18:02:30 +01006385HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6386 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6387 MethodReference target_method) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006388 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6389 // We disable pc-relative load when there is an irreducible loop, as the optimization
6390 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006391 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6392 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006393 if (GetGraph()->HasIrreducibleLoops() &&
6394 (dispatch_info.method_load_kind ==
6395 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6396 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6397 }
6398
6399 if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
Vladimir Markodc151b22015-10-15 18:02:30 +01006400 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6401 if (&outer_dex_file != target_method.dex_file) {
6402 // Calls across dex files are more likely to exceed the available BL range,
6403 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6404 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6405 (desired_dispatch_info.method_load_kind ==
6406 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6407 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6408 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6409 return HInvokeStaticOrDirect::DispatchInfo {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006410 dispatch_info.method_load_kind,
Vladimir Markodc151b22015-10-15 18:02:30 +01006411 code_ptr_location,
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006412 dispatch_info.method_load_data,
Vladimir Markodc151b22015-10-15 18:02:30 +01006413 0u
6414 };
6415 }
6416 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006417 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01006418}
6419
Vladimir Markob4536b72015-11-24 13:45:23 +00006420Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6421 Register temp) {
6422 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6423 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6424 if (!invoke->GetLocations()->Intrinsified()) {
6425 return location.AsRegister<Register>();
6426 }
6427 // For intrinsics we allow any location, so it may be on the stack.
6428 if (!location.IsRegister()) {
6429 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6430 return temp;
6431 }
6432 // For register locations, check if the register was saved. If so, get it from the stack.
6433 // Note: There is a chance that the register was saved but not overwritten, so we could
6434 // save one load. However, since this is just an intrinsic slow path we prefer this
6435 // simple and more robust approach rather that trying to determine if that's the case.
6436 SlowPathCode* slow_path = GetCurrentSlowPath();
6437 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6438 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6439 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6440 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6441 return temp;
6442 }
6443 return location.AsRegister<Register>();
6444}
6445
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006446void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006447 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006448 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006449 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6450 // LR = code address from literal pool with link-time patch.
6451 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006452 break;
6453 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6454 // LR = invoke->GetDirectCodePtr();
6455 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006456 break;
6457 default:
6458 break;
6459 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006460
Vladimir Marko58155012015-08-19 12:49:41 +00006461 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6462 switch (invoke->GetMethodLoadKind()) {
6463 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6464 // temp = thread->string_init_entrypoint
6465 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6466 break;
6467 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006468 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006469 break;
6470 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6471 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6472 break;
6473 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6474 __ LoadLiteral(temp.AsRegister<Register>(),
6475 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6476 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006477 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6478 HArmDexCacheArraysBase* base =
6479 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6480 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6481 temp.AsRegister<Register>());
6482 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6483 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6484 break;
6485 }
Vladimir Marko58155012015-08-19 12:49:41 +00006486 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006487 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006488 Register method_reg;
6489 Register reg = temp.AsRegister<Register>();
6490 if (current_method.IsRegister()) {
6491 method_reg = current_method.AsRegister<Register>();
6492 } else {
6493 DCHECK(invoke->GetLocations()->Intrinsified());
6494 DCHECK(!current_method.IsValid());
6495 method_reg = reg;
6496 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6497 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006498 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6499 __ LoadFromOffset(kLoadWord,
6500 reg,
6501 method_reg,
6502 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01006503 // temp = temp[index_in_cache];
6504 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6505 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00006506 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6507 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006508 }
Vladimir Marko58155012015-08-19 12:49:41 +00006509 }
6510
6511 switch (invoke->GetCodePtrLocation()) {
6512 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6513 __ bl(GetFrameEntryLabel());
6514 break;
6515 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006516 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006517 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006518 // Arbitrarily branch to the BL itself, override at link time.
6519 __ bl(&relative_call_patches_.back().label);
6520 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006521 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6522 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6523 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006524 // LR()
6525 __ blx(LR);
6526 break;
6527 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6528 // LR = callee_method->entry_point_from_quick_compiled_code_
6529 __ LoadFromOffset(
6530 kLoadWord, LR, callee_method.AsRegister<Register>(),
6531 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6532 // LR()
6533 __ blx(LR);
6534 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006535 }
6536
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006537 DCHECK(!IsLeafMethod());
6538}
6539
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006540void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6541 Register temp = temp_location.AsRegister<Register>();
6542 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6543 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006544
6545 // Use the calling convention instead of the location of the receiver, as
6546 // intrinsics may have put the receiver in a different register. In the intrinsics
6547 // slow path, the arguments have been moved to the right place, so here we are
6548 // guaranteed that the receiver is the first register of the calling convention.
6549 InvokeDexCallingConvention calling_convention;
6550 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006551 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006552 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006553 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006554 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006555 // Instead of simply (possibly) unpoisoning `temp` here, we should
6556 // emit a read barrier for the previous class reference load.
6557 // However this is not required in practice, as this is an
6558 // intermediate/temporary reference and because the current
6559 // concurrent copying collector keeps the from-space memory
6560 // intact/accessible until the end of the marking phase (the
6561 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006562 __ MaybeUnpoisonHeapReference(temp);
6563 // temp = temp->GetMethodAt(method_offset);
6564 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6565 kArmWordSize).Int32Value();
6566 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6567 // LR = temp->GetEntryPoint();
6568 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6569 // LR();
6570 __ blx(LR);
6571}
6572
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006573CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6574 const DexFile& dex_file, uint32_t string_index) {
6575 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6576}
6577
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006578CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
6579 const DexFile& dex_file, uint32_t type_index) {
6580 return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
6581}
6582
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006583CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6584 const DexFile& dex_file, uint32_t element_offset) {
6585 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6586}
6587
6588CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6589 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6590 patches->emplace_back(dex_file, offset_or_index);
6591 return &patches->back();
6592}
6593
6594Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6595 uint32_t string_index) {
6596 return boot_image_string_patches_.GetOrCreate(
6597 StringReference(&dex_file, string_index),
6598 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6599}
6600
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006601Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
6602 uint32_t type_index) {
6603 return boot_image_type_patches_.GetOrCreate(
6604 TypeReference(&dex_file, type_index),
6605 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6606}
6607
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006608Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6609 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6610 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6611 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6612}
6613
6614Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6615 return DeduplicateUint32Literal(address, &uint32_literals_);
6616}
6617
Vladimir Marko58155012015-08-19 12:49:41 +00006618void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6619 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006620 size_t size =
6621 method_patches_.size() +
6622 call_patches_.size() +
6623 relative_call_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006624 /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6625 boot_image_string_patches_.size() +
6626 /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006627 boot_image_type_patches_.size() +
6628 /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006629 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006630 linker_patches->reserve(size);
6631 for (const auto& entry : method_patches_) {
6632 const MethodReference& target_method = entry.first;
6633 Literal* literal = entry.second;
6634 DCHECK(literal->GetLabel()->IsBound());
6635 uint32_t literal_offset = literal->GetLabel()->Position();
6636 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6637 target_method.dex_file,
6638 target_method.dex_method_index));
6639 }
6640 for (const auto& entry : call_patches_) {
6641 const MethodReference& target_method = entry.first;
6642 Literal* literal = entry.second;
6643 DCHECK(literal->GetLabel()->IsBound());
6644 uint32_t literal_offset = literal->GetLabel()->Position();
6645 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6646 target_method.dex_file,
6647 target_method.dex_method_index));
6648 }
6649 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6650 uint32_t literal_offset = info.label.Position();
6651 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6652 info.target_method.dex_file,
6653 info.target_method.dex_method_index));
6654 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006655 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6656 const DexFile& dex_file = info.target_dex_file;
6657 size_t base_element_offset = info.offset_or_index;
6658 DCHECK(info.add_pc_label.IsBound());
6659 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006660 // Add MOVW patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006661 DCHECK(info.movw_label.IsBound());
6662 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006663 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6664 &dex_file,
6665 add_pc_offset,
6666 base_element_offset));
6667 // Add MOVT patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006668 DCHECK(info.movt_label.IsBound());
6669 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006670 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6671 &dex_file,
6672 add_pc_offset,
6673 base_element_offset));
6674 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006675 for (const auto& entry : boot_image_string_patches_) {
6676 const StringReference& target_string = entry.first;
6677 Literal* literal = entry.second;
6678 DCHECK(literal->GetLabel()->IsBound());
6679 uint32_t literal_offset = literal->GetLabel()->Position();
6680 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6681 target_string.dex_file,
6682 target_string.string_index));
6683 }
6684 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6685 const DexFile& dex_file = info.target_dex_file;
6686 uint32_t string_index = info.offset_or_index;
6687 DCHECK(info.add_pc_label.IsBound());
6688 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6689 // Add MOVW patch.
6690 DCHECK(info.movw_label.IsBound());
6691 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6692 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6693 &dex_file,
6694 add_pc_offset,
6695 string_index));
6696 // Add MOVT patch.
6697 DCHECK(info.movt_label.IsBound());
6698 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6699 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6700 &dex_file,
6701 add_pc_offset,
6702 string_index));
6703 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006704 for (const auto& entry : boot_image_type_patches_) {
6705 const TypeReference& target_type = entry.first;
6706 Literal* literal = entry.second;
6707 DCHECK(literal->GetLabel()->IsBound());
6708 uint32_t literal_offset = literal->GetLabel()->Position();
6709 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
6710 target_type.dex_file,
6711 target_type.type_index));
6712 }
6713 for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
6714 const DexFile& dex_file = info.target_dex_file;
6715 uint32_t type_index = info.offset_or_index;
6716 DCHECK(info.add_pc_label.IsBound());
6717 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6718 // Add MOVW patch.
6719 DCHECK(info.movw_label.IsBound());
6720 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6721 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset,
6722 &dex_file,
6723 add_pc_offset,
6724 type_index));
6725 // Add MOVT patch.
6726 DCHECK(info.movt_label.IsBound());
6727 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6728 linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset,
6729 &dex_file,
6730 add_pc_offset,
6731 type_index));
6732 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006733 for (const auto& entry : boot_image_address_patches_) {
6734 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6735 Literal* literal = entry.second;
6736 DCHECK(literal->GetLabel()->IsBound());
6737 uint32_t literal_offset = literal->GetLabel()->Position();
6738 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6739 }
6740}
6741
6742Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6743 return map->GetOrCreate(
6744 value,
6745 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00006746}
6747
6748Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6749 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006750 return map->GetOrCreate(
6751 target_method,
6752 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00006753}
6754
6755Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6756 return DeduplicateMethodLiteral(target_method, &method_patches_);
6757}
6758
6759Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6760 return DeduplicateMethodLiteral(target_method, &call_patches_);
6761}
6762
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03006763void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6764 LocationSummary* locations =
6765 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6766 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6767 Location::RequiresRegister());
6768 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6769 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6770 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6771}
6772
6773void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6774 LocationSummary* locations = instr->GetLocations();
6775 Register res = locations->Out().AsRegister<Register>();
6776 Register accumulator =
6777 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6778 Register mul_left =
6779 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6780 Register mul_right =
6781 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6782
6783 if (instr->GetOpKind() == HInstruction::kAdd) {
6784 __ mla(res, mul_left, mul_right, accumulator);
6785 } else {
6786 __ mls(res, mul_left, mul_right, accumulator);
6787 }
6788}
6789
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006790void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006791 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006792 LOG(FATAL) << "Unreachable";
6793}
6794
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006795void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006796 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006797 LOG(FATAL) << "Unreachable";
6798}
6799
Mark Mendellfe57faa2015-09-18 09:26:15 -04006800// Simple implementation of packed switch - generate cascaded compare/jumps.
6801void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6802 LocationSummary* locations =
6803 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6804 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006805 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006806 codegen_->GetAssembler()->IsThumb()) {
6807 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6808 if (switch_instr->GetStartValue() != 0) {
6809 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6810 }
6811 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006812}
6813
6814void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6815 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006816 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006817 LocationSummary* locations = switch_instr->GetLocations();
6818 Register value_reg = locations->InAt(0).AsRegister<Register>();
6819 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6820
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006821 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006822 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006823 Register temp_reg = IP;
6824 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6825 // the immediate, because IP is used as the destination register. For the other
6826 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6827 // and they can be encoded in the instruction without making use of IP register.
6828 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6829
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006830 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006831 // Jump to successors[0] if value == lower_bound.
6832 __ b(codegen_->GetLabelOf(successors[0]), EQ);
6833 int32_t last_index = 0;
6834 for (; num_entries - last_index > 2; last_index += 2) {
6835 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6836 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6837 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6838 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6839 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6840 }
6841 if (num_entries - last_index == 2) {
6842 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00006843 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006844 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006845 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006846
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006847 // And the default for any other value.
6848 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6849 __ b(codegen_->GetLabelOf(default_block));
6850 }
6851 } else {
6852 // Create a table lookup.
6853 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6854
6855 // Materialize a pointer to the switch table
6856 std::vector<Label*> labels(num_entries);
6857 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6858 for (uint32_t i = 0; i < num_entries; i++) {
6859 labels[i] = codegen_->GetLabelOf(successors[i]);
6860 }
6861 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6862
6863 // Remove the bias.
6864 Register key_reg;
6865 if (lower_bound != 0) {
6866 key_reg = locations->GetTemp(1).AsRegister<Register>();
6867 __ AddConstant(key_reg, value_reg, -lower_bound);
6868 } else {
6869 key_reg = value_reg;
6870 }
6871
6872 // Check whether the value is in the table, jump to default block if not.
6873 __ CmpConstant(key_reg, num_entries - 1);
6874 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6875
6876 // Load the displacement from the table.
6877 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6878
6879 // Dispatch is a direct add to the PC (for Thumb2).
6880 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006881 }
6882}
6883
Vladimir Markob4536b72015-11-24 13:45:23 +00006884void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6885 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6886 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00006887}
6888
6889void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6890 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006891 CodeGeneratorARM::PcRelativePatchInfo* labels =
6892 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00006893 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006894 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006895 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006896 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006897 __ BindTrackedLabel(&labels->add_pc_label);
6898 __ add(base_reg, base_reg, ShifterOperand(PC));
6899}
6900
Andreas Gampe85b62f22015-09-09 13:15:38 -07006901void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6902 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00006903 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07006904 return;
6905 }
6906
6907 DCHECK_NE(type, Primitive::kPrimVoid);
6908
6909 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6910 if (return_loc.Equals(trg)) {
6911 return;
6912 }
6913
6914 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6915 // with the last branch.
6916 if (type == Primitive::kPrimLong) {
6917 HParallelMove parallel_move(GetGraph()->GetArena());
6918 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6919 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6920 GetMoveResolver()->EmitNativeCode(&parallel_move);
6921 } else if (type == Primitive::kPrimDouble) {
6922 HParallelMove parallel_move(GetGraph()->GetArena());
6923 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6924 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6925 GetMoveResolver()->EmitNativeCode(&parallel_move);
6926 } else {
6927 // Let the parallel move resolver take care of all of this.
6928 HParallelMove parallel_move(GetGraph()->GetArena());
6929 parallel_move.AddMove(return_loc, trg, type, nullptr);
6930 GetMoveResolver()->EmitNativeCode(&parallel_move);
6931 }
6932}
6933
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006934void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
6935 LocationSummary* locations =
6936 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6937 locations->SetInAt(0, Location::RequiresRegister());
6938 locations->SetOut(Location::RequiresRegister());
6939}
6940
6941void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
6942 LocationSummary* locations = instruction->GetLocations();
6943 uint32_t method_offset = 0;
Vladimir Markoa1de9182016-02-25 11:37:38 +00006944 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006945 method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6946 instruction->GetIndex(), kArmPointerSize).SizeValue();
6947 } else {
Nelli Kimbadee982016-05-13 13:08:53 +03006948 __ LoadFromOffset(kLoadWord, locations->Out().AsRegister<Register>(),
6949 locations->InAt(0).AsRegister<Register>(),
6950 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
6951 method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity50706432016-06-14 11:31:04 -07006952 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006953 }
6954 __ LoadFromOffset(kLoadWord,
6955 locations->Out().AsRegister<Register>(),
6956 locations->InAt(0).AsRegister<Register>(),
6957 method_offset);
6958}
6959
Roland Levillain4d027112015-07-01 15:41:14 +01006960#undef __
6961#undef QUICK_ENTRY_POINT
6962
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006963} // namespace arm
6964} // namespace art