blob: 7fe396019f4c56f8e4b9028fedb82b0ca269e8c3 [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() ||
Roland Levillain3d312422016-06-23 13:53:42 +0100430 instruction_->IsCheckCast() ||
431 ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
432 instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +0000433 << "Unexpected instruction in read barrier marking slow path: "
434 << instruction_->DebugName();
435
436 __ Bind(GetEntryLabel());
437 SaveLiveRegisters(codegen, locations);
438
439 InvokeRuntimeCallingConvention calling_convention;
440 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
441 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
442 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
443 instruction_,
444 instruction_->GetDexPc(),
445 this);
446 CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
447 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
448
449 RestoreLiveRegisters(codegen, locations);
450 __ b(GetExitLabel());
451 }
452
453 private:
Roland Levillainc9285912015-12-18 10:38:42 +0000454 const Location out_;
455 const Location obj_;
456
457 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
458};
459
Roland Levillain3b359c72015-11-17 19:35:12 +0000460// Slow path generating a read barrier for a heap reference.
461class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
462 public:
463 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
464 Location out,
465 Location ref,
466 Location obj,
467 uint32_t offset,
468 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000469 : SlowPathCode(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000470 out_(out),
471 ref_(ref),
472 obj_(obj),
473 offset_(offset),
474 index_(index) {
475 DCHECK(kEmitCompilerReadBarrier);
476 // If `obj` is equal to `out` or `ref`, it means the initial object
477 // has been overwritten by (or after) the heap object reference load
478 // to be instrumented, e.g.:
479 //
480 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000481 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000482 //
483 // In that case, we have lost the information about the original
484 // object, and the emitted read barrier cannot work properly.
485 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
486 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
487 }
488
489 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
490 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
491 LocationSummary* locations = instruction_->GetLocations();
492 Register reg_out = out_.AsRegister<Register>();
493 DCHECK(locations->CanCall());
494 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +0100495 DCHECK(instruction_->IsInstanceFieldGet() ||
496 instruction_->IsStaticFieldGet() ||
497 instruction_->IsArrayGet() ||
498 instruction_->IsInstanceOf() ||
499 instruction_->IsCheckCast() ||
500 ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
Roland Levillainc9285912015-12-18 10:38:42 +0000501 instruction_->GetLocations()->Intrinsified()))
502 << "Unexpected instruction in read barrier for heap reference slow path: "
503 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000504
505 __ Bind(GetEntryLabel());
506 SaveLiveRegisters(codegen, locations);
507
508 // We may have to change the index's value, but as `index_` is a
509 // constant member (like other "inputs" of this slow path),
510 // introduce a copy of it, `index`.
511 Location index = index_;
512 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +0100513 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +0000514 if (instruction_->IsArrayGet()) {
515 // Compute the actual memory offset and store it in `index`.
516 Register index_reg = index_.AsRegister<Register>();
517 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
518 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
519 // We are about to change the value of `index_reg` (see the
520 // calls to art::arm::Thumb2Assembler::Lsl and
521 // art::arm::Thumb2Assembler::AddConstant below), but it has
522 // not been saved by the previous call to
523 // art::SlowPathCode::SaveLiveRegisters, as it is a
524 // callee-save register --
525 // art::SlowPathCode::SaveLiveRegisters does not consider
526 // callee-save registers, as it has been designed with the
527 // assumption that callee-save registers are supposed to be
528 // handled by the called function. So, as a callee-save
529 // register, `index_reg` _would_ eventually be saved onto
530 // the stack, but it would be too late: we would have
531 // changed its value earlier. Therefore, we manually save
532 // it here into another freely available register,
533 // `free_reg`, chosen of course among the caller-save
534 // registers (as a callee-save `free_reg` register would
535 // exhibit the same problem).
536 //
537 // Note we could have requested a temporary register from
538 // the register allocator instead; but we prefer not to, as
539 // this is a slow path, and we know we can find a
540 // caller-save register that is available.
541 Register free_reg = FindAvailableCallerSaveRegister(codegen);
542 __ Mov(free_reg, index_reg);
543 index_reg = free_reg;
544 index = Location::RegisterLocation(index_reg);
545 } else {
546 // The initial register stored in `index_` has already been
547 // saved in the call to art::SlowPathCode::SaveLiveRegisters
548 // (as it is not a callee-save register), so we can freely
549 // use it.
550 }
551 // Shifting the index value contained in `index_reg` by the scale
552 // factor (2) cannot overflow in practice, as the runtime is
553 // unable to allocate object arrays with a size larger than
554 // 2^26 - 1 (that is, 2^28 - 4 bytes).
555 __ Lsl(index_reg, index_reg, TIMES_4);
556 static_assert(
557 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
558 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
559 __ AddConstant(index_reg, index_reg, offset_);
560 } else {
Roland Levillain3d312422016-06-23 13:53:42 +0100561 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
562 // intrinsics, `index_` is not shifted by a scale factor of 2
563 // (as in the case of ArrayGet), as it is actually an offset
564 // to an object field within an object.
565 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000566 DCHECK(instruction_->GetLocations()->Intrinsified());
567 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
568 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
569 << instruction_->AsInvoke()->GetIntrinsic();
570 DCHECK_EQ(offset_, 0U);
571 DCHECK(index_.IsRegisterPair());
572 // UnsafeGet's offset location is a register pair, the low
573 // part contains the correct offset.
574 index = index_.ToLow();
575 }
576 }
577
578 // We're moving two or three locations to locations that could
579 // overlap, so we need a parallel move resolver.
580 InvokeRuntimeCallingConvention calling_convention;
581 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
582 parallel_move.AddMove(ref_,
583 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
584 Primitive::kPrimNot,
585 nullptr);
586 parallel_move.AddMove(obj_,
587 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
588 Primitive::kPrimNot,
589 nullptr);
590 if (index.IsValid()) {
591 parallel_move.AddMove(index,
592 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
593 Primitive::kPrimInt,
594 nullptr);
595 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
596 } else {
597 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
598 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
599 }
600 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
601 instruction_,
602 instruction_->GetDexPc(),
603 this);
604 CheckEntrypointTypes<
605 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
606 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
607
608 RestoreLiveRegisters(codegen, locations);
609 __ b(GetExitLabel());
610 }
611
612 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
613
614 private:
615 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
616 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
617 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
618 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
619 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
620 return static_cast<Register>(i);
621 }
622 }
623 // We shall never fail to find a free caller-save register, as
624 // there are more than two core caller-save registers on ARM
625 // (meaning it is possible to find one which is different from
626 // `ref` and `obj`).
627 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
628 LOG(FATAL) << "Could not find a free caller-save register";
629 UNREACHABLE();
630 }
631
Roland Levillain3b359c72015-11-17 19:35:12 +0000632 const Location out_;
633 const Location ref_;
634 const Location obj_;
635 const uint32_t offset_;
636 // An additional location containing an index to an array.
637 // Only used for HArrayGet and the UnsafeGetObject &
638 // UnsafeGetObjectVolatile intrinsics.
639 const Location index_;
640
641 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
642};
643
644// Slow path generating a read barrier for a GC root.
645class ReadBarrierForRootSlowPathARM : public SlowPathCode {
646 public:
647 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000648 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +0000649 DCHECK(kEmitCompilerReadBarrier);
650 }
Roland Levillain3b359c72015-11-17 19:35:12 +0000651
652 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
653 LocationSummary* locations = instruction_->GetLocations();
654 Register reg_out = out_.AsRegister<Register>();
655 DCHECK(locations->CanCall());
656 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +0000657 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
658 << "Unexpected instruction in read barrier for GC root slow path: "
659 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000660
661 __ Bind(GetEntryLabel());
662 SaveLiveRegisters(codegen, locations);
663
664 InvokeRuntimeCallingConvention calling_convention;
665 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
666 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
667 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
668 instruction_,
669 instruction_->GetDexPc(),
670 this);
671 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
672 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
673
674 RestoreLiveRegisters(codegen, locations);
675 __ b(GetExitLabel());
676 }
677
678 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
679
680 private:
Roland Levillain3b359c72015-11-17 19:35:12 +0000681 const Location out_;
682 const Location root_;
683
684 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
685};
686
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000687#undef __
Chih-Hung Hsiehfba39972016-05-11 11:26:48 -0700688// NOLINT on __ macro to suppress wrong warning/fix from clang-tidy.
689#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
Dave Allison20dfc792014-06-16 20:44:29 -0700690
Aart Bike9f37602015-10-09 11:15:55 -0700691inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700692 switch (cond) {
693 case kCondEQ: return EQ;
694 case kCondNE: return NE;
695 case kCondLT: return LT;
696 case kCondLE: return LE;
697 case kCondGT: return GT;
698 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700699 case kCondB: return LO;
700 case kCondBE: return LS;
701 case kCondA: return HI;
702 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700703 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100704 LOG(FATAL) << "Unreachable";
705 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700706}
707
Aart Bike9f37602015-10-09 11:15:55 -0700708// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100709inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700710 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100711 case kCondEQ: return EQ;
712 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700713 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100714 case kCondLT: return LO;
715 case kCondLE: return LS;
716 case kCondGT: return HI;
717 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700718 // Unsigned remain unchanged.
719 case kCondB: return LO;
720 case kCondBE: return LS;
721 case kCondA: return HI;
722 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700723 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100724 LOG(FATAL) << "Unreachable";
725 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700726}
727
Vladimir Markod6e069b2016-01-18 11:11:01 +0000728inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
729 // The ARM condition codes can express all the necessary branches, see the
730 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
731 // There is no dex instruction or HIR that would need the missing conditions
732 // "equal or unordered" or "not equal".
733 switch (cond) {
734 case kCondEQ: return EQ;
735 case kCondNE: return NE /* unordered */;
736 case kCondLT: return gt_bias ? CC : LT /* unordered */;
737 case kCondLE: return gt_bias ? LS : LE /* unordered */;
738 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
739 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
740 default:
741 LOG(FATAL) << "UNREACHABLE";
742 UNREACHABLE();
743 }
744}
745
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100746void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100747 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100748}
749
750void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100751 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100752}
753
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100754size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
755 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
756 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100757}
758
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100759size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
760 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
761 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100762}
763
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000764size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
765 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
766 return kArmWordSize;
767}
768
769size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
770 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
771 return kArmWordSize;
772}
773
Calin Juravle34166012014-12-19 17:22:29 +0000774CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000775 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100776 const CompilerOptions& compiler_options,
777 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000778 : CodeGenerator(graph,
779 kNumberOfCoreRegisters,
780 kNumberOfSRegisters,
781 kNumberOfRegisterPairs,
782 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
783 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000784 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
785 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100786 compiler_options,
787 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100788 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100789 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100790 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100791 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100792 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +0000793 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000794 uint32_literals_(std::less<uint32_t>(),
795 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko5233f932015-09-29 19:01:15 +0100796 method_patches_(MethodReferenceComparator(),
797 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
798 call_patches_(MethodReferenceComparator(),
799 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000800 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000801 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
802 boot_image_string_patches_(StringReferenceValueComparator(),
803 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
804 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
805 boot_image_address_patches_(std::less<uint32_t>(),
806 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700807 // Always save the LR register to mimic Quick.
808 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100809}
810
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000811void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
812 // Ensure that we fix up branches and literal loads and emit the literal pool.
813 __ FinalizeCode();
814
815 // Adjust native pc offsets in stack maps.
816 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
817 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
818 uint32_t new_position = __ GetAdjustedPosition(old_position);
819 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
820 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100821 // Adjust pc offsets for the disassembly information.
822 if (disasm_info_ != nullptr) {
823 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
824 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
825 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
826 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
827 it.second.start = __ GetAdjustedPosition(it.second.start);
828 it.second.end = __ GetAdjustedPosition(it.second.end);
829 }
830 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
831 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
832 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
833 }
834 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000835
836 CodeGenerator::Finalize(allocator);
837}
838
David Brazdil58282f42016-01-14 12:45:10 +0000839void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100840 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100841 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100842
843 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100844 blocked_core_registers_[SP] = true;
845 blocked_core_registers_[LR] = true;
846 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100847
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100848 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100849 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100850
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100851 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100852 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100853
David Brazdil58282f42016-01-14 12:45:10 +0000854 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100855 // Stubs do not save callee-save floating point registers. If the graph
856 // is debuggable, we need to deal with these registers differently. For
857 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000858 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
859 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
860 }
861 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100862
863 UpdateBlockedPairRegisters();
864}
865
866void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
867 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
868 ArmManagedRegister current =
869 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
870 if (blocked_core_registers_[current.AsRegisterPairLow()]
871 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
872 blocked_register_pairs_[i] = true;
873 }
874 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100875}
876
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100877InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -0800878 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100879 assembler_(codegen->GetAssembler()),
880 codegen_(codegen) {}
881
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000882void CodeGeneratorARM::ComputeSpillMask() {
883 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
884 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +0000885 // There is no easy instruction to restore just the PC on thumb2. We spill and
886 // restore another arbitrary register.
887 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000888 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
889 // We use vpush and vpop for saving and restoring floating point registers, which take
890 // a SRegister and the number of registers to save/restore after that SRegister. We
891 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
892 // but in the range.
893 if (fpu_spill_mask_ != 0) {
894 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
895 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
896 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
897 fpu_spill_mask_ |= (1 << i);
898 }
899 }
900}
901
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100902static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100903 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100904}
905
906static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100907 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100908}
909
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000910void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000911 bool skip_overflow_check =
912 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000913 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000914 __ Bind(&frame_entry_label_);
915
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000916 if (HasEmptyFrame()) {
917 return;
918 }
919
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100920 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000921 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
922 __ LoadFromOffset(kLoadWord, IP, IP, 0);
923 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100924 }
925
Andreas Gampe501fd632015-09-10 16:11:06 -0700926 __ PushList(core_spill_mask_);
927 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
928 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000929 if (fpu_spill_mask_ != 0) {
930 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
931 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100932 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100933 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000934 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100935 int adjust = GetFrameSize() - FrameEntrySpillSize();
936 __ AddConstant(SP, -adjust);
937 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100938 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000939}
940
941void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000942 if (HasEmptyFrame()) {
943 __ bx(LR);
944 return;
945 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100946 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100947 int adjust = GetFrameSize() - FrameEntrySpillSize();
948 __ AddConstant(SP, adjust);
949 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000950 if (fpu_spill_mask_ != 0) {
951 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
952 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100953 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
954 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000955 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700956 // Pop LR into PC to return.
957 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
958 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
959 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100960 __ cfi().RestoreState();
961 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000962}
963
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100964void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700965 Label* label = GetLabelOf(block);
966 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000967}
968
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100969Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100970 switch (type) {
971 case Primitive::kPrimBoolean:
972 case Primitive::kPrimByte:
973 case Primitive::kPrimChar:
974 case Primitive::kPrimShort:
975 case Primitive::kPrimInt:
976 case Primitive::kPrimNot: {
977 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000978 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100979 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100980 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100981 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000982 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100983 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100984 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100985
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000986 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100987 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000988 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100989 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000990 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100991 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000992 if (calling_convention.GetRegisterAt(index) == R1) {
993 // Skip R1, and use R2_R3 instead.
994 gp_index_++;
995 index++;
996 }
997 }
998 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
999 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001000 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001001
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001002 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001003 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001004 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001005 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1006 }
1007 }
1008
1009 case Primitive::kPrimFloat: {
1010 uint32_t stack_index = stack_index_++;
1011 if (float_index_ % 2 == 0) {
1012 float_index_ = std::max(double_index_, float_index_);
1013 }
1014 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1015 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1016 } else {
1017 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1018 }
1019 }
1020
1021 case Primitive::kPrimDouble: {
1022 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1023 uint32_t stack_index = stack_index_;
1024 stack_index_ += 2;
1025 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1026 uint32_t index = double_index_;
1027 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001028 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001029 calling_convention.GetFpuRegisterAt(index),
1030 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001031 DCHECK(ExpectedPairLayout(result));
1032 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001033 } else {
1034 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001035 }
1036 }
1037
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001038 case Primitive::kPrimVoid:
1039 LOG(FATAL) << "Unexpected parameter type " << type;
1040 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001041 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001042 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001043}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001044
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001045Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001046 switch (type) {
1047 case Primitive::kPrimBoolean:
1048 case Primitive::kPrimByte:
1049 case Primitive::kPrimChar:
1050 case Primitive::kPrimShort:
1051 case Primitive::kPrimInt:
1052 case Primitive::kPrimNot: {
1053 return Location::RegisterLocation(R0);
1054 }
1055
1056 case Primitive::kPrimFloat: {
1057 return Location::FpuRegisterLocation(S0);
1058 }
1059
1060 case Primitive::kPrimLong: {
1061 return Location::RegisterPairLocation(R0, R1);
1062 }
1063
1064 case Primitive::kPrimDouble: {
1065 return Location::FpuRegisterPairLocation(S0, S1);
1066 }
1067
1068 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001069 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001070 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001071
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001072 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001073}
1074
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001075Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1076 return Location::RegisterLocation(kMethodRegisterArgument);
1077}
1078
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001079void CodeGeneratorARM::Move32(Location destination, Location source) {
1080 if (source.Equals(destination)) {
1081 return;
1082 }
1083 if (destination.IsRegister()) {
1084 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001085 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001086 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001087 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001088 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001089 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001090 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001091 } else if (destination.IsFpuRegister()) {
1092 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001093 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001094 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001095 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001097 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001099 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001100 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001101 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001104 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001105 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001106 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001107 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1108 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001109 }
1110 }
1111}
1112
1113void CodeGeneratorARM::Move64(Location destination, Location source) {
1114 if (source.Equals(destination)) {
1115 return;
1116 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001117 if (destination.IsRegisterPair()) {
1118 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001119 EmitParallelMoves(
1120 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1121 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001122 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001123 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001124 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1125 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001126 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001127 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001128 } else if (source.IsFpuRegisterPair()) {
1129 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1130 destination.AsRegisterPairHigh<Register>(),
1131 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001132 } else {
1133 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001134 DCHECK(ExpectedPairLayout(destination));
1135 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1136 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001137 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001138 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001139 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001140 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1141 SP,
1142 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001143 } else if (source.IsRegisterPair()) {
1144 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1145 source.AsRegisterPairLow<Register>(),
1146 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001147 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001148 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001149 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001150 } else {
1151 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001152 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001153 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001154 if (source.AsRegisterPairLow<Register>() == R1) {
1155 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001156 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1157 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001158 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001159 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001160 SP, destination.GetStackIndex());
1161 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001162 } else if (source.IsFpuRegisterPair()) {
1163 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1164 SP,
1165 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001166 } else {
1167 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001168 EmitParallelMoves(
1169 Location::StackSlot(source.GetStackIndex()),
1170 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001171 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001172 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001173 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1174 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001175 }
1176 }
1177}
1178
Calin Juravle175dc732015-08-25 15:42:32 +01001179void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1180 DCHECK(location.IsRegister());
1181 __ LoadImmediate(location.AsRegister<Register>(), value);
1182}
1183
Calin Juravlee460d1d2015-09-29 04:52:17 +01001184void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001185 HParallelMove move(GetGraph()->GetArena());
1186 move.AddMove(src, dst, dst_type, nullptr);
1187 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001188}
1189
1190void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1191 if (location.IsRegister()) {
1192 locations->AddTemp(location);
1193 } else if (location.IsRegisterPair()) {
1194 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1195 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1196 } else {
1197 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1198 }
1199}
1200
Calin Juravle175dc732015-08-25 15:42:32 +01001201void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1202 HInstruction* instruction,
1203 uint32_t dex_pc,
1204 SlowPathCode* slow_path) {
1205 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1206 instruction,
1207 dex_pc,
1208 slow_path);
1209}
1210
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001211void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1212 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001213 uint32_t dex_pc,
1214 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001215 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001216 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1217 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001218 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001219}
1220
David Brazdilfc6a86a2015-06-26 10:33:45 +00001221void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001222 DCHECK(!successor->IsExitBlock());
1223
1224 HBasicBlock* block = got->GetBlock();
1225 HInstruction* previous = got->GetPrevious();
1226
1227 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001228 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001229 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1230 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1231 return;
1232 }
1233
1234 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1235 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1236 }
1237 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001238 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001239 }
1240}
1241
David Brazdilfc6a86a2015-06-26 10:33:45 +00001242void LocationsBuilderARM::VisitGoto(HGoto* got) {
1243 got->SetLocations(nullptr);
1244}
1245
1246void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1247 HandleGoto(got, got->GetSuccessor());
1248}
1249
1250void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1251 try_boundary->SetLocations(nullptr);
1252}
1253
1254void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1255 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1256 if (!successor->IsExitBlock()) {
1257 HandleGoto(try_boundary, successor);
1258 }
1259}
1260
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001261void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001262 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001263}
1264
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001265void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001266}
1267
Roland Levillain4fa13f62015-07-06 18:11:54 +01001268void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1269 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001270 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001271 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001272 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001273}
1274
1275void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1276 Label* true_label,
1277 Label* false_label) {
1278 LocationSummary* locations = cond->GetLocations();
1279 Location left = locations->InAt(0);
1280 Location right = locations->InAt(1);
1281 IfCondition if_cond = cond->GetCondition();
1282
1283 Register left_high = left.AsRegisterPairHigh<Register>();
1284 Register left_low = left.AsRegisterPairLow<Register>();
1285 IfCondition true_high_cond = if_cond;
1286 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001287 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001288
1289 // Set the conditions for the test, remembering that == needs to be
1290 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001291 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001292 switch (if_cond) {
1293 case kCondEQ:
1294 case kCondNE:
1295 // Nothing to do.
1296 break;
1297 case kCondLT:
1298 false_high_cond = kCondGT;
1299 break;
1300 case kCondLE:
1301 true_high_cond = kCondLT;
1302 break;
1303 case kCondGT:
1304 false_high_cond = kCondLT;
1305 break;
1306 case kCondGE:
1307 true_high_cond = kCondGT;
1308 break;
Aart Bike9f37602015-10-09 11:15:55 -07001309 case kCondB:
1310 false_high_cond = kCondA;
1311 break;
1312 case kCondBE:
1313 true_high_cond = kCondB;
1314 break;
1315 case kCondA:
1316 false_high_cond = kCondB;
1317 break;
1318 case kCondAE:
1319 true_high_cond = kCondA;
1320 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001321 }
1322 if (right.IsConstant()) {
1323 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1324 int32_t val_low = Low32Bits(value);
1325 int32_t val_high = High32Bits(value);
1326
Vladimir Markoac6ac102015-12-17 12:14:00 +00001327 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001328 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001329 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001330 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001331 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001332 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001333 __ b(true_label, ARMCondition(true_high_cond));
1334 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001335 }
1336 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001337 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001338 } else {
1339 Register right_high = right.AsRegisterPairHigh<Register>();
1340 Register right_low = right.AsRegisterPairLow<Register>();
1341
1342 __ cmp(left_high, ShifterOperand(right_high));
1343 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001344 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001345 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001346 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001347 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001348 __ b(true_label, ARMCondition(true_high_cond));
1349 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001350 }
1351 // Must be equal high, so compare the lows.
1352 __ cmp(left_low, ShifterOperand(right_low));
1353 }
1354 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001355 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001356 __ b(true_label, final_condition);
1357}
1358
David Brazdil0debae72015-11-12 18:37:00 +00001359void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1360 Label* true_target_in,
1361 Label* false_target_in) {
1362 // Generated branching requires both targets to be explicit. If either of the
1363 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1364 Label fallthrough_target;
1365 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1366 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1367
Roland Levillain4fa13f62015-07-06 18:11:54 +01001368 LocationSummary* locations = condition->GetLocations();
1369 Location left = locations->InAt(0);
1370 Location right = locations->InAt(1);
1371
Roland Levillain4fa13f62015-07-06 18:11:54 +01001372 Primitive::Type type = condition->InputAt(0)->GetType();
1373 switch (type) {
1374 case Primitive::kPrimLong:
1375 GenerateLongComparesAndJumps(condition, true_target, false_target);
1376 break;
1377 case Primitive::kPrimFloat:
1378 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1379 GenerateFPJumps(condition, true_target, false_target);
1380 break;
1381 case Primitive::kPrimDouble:
1382 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1383 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1384 GenerateFPJumps(condition, true_target, false_target);
1385 break;
1386 default:
1387 LOG(FATAL) << "Unexpected compare type " << type;
1388 }
1389
David Brazdil0debae72015-11-12 18:37:00 +00001390 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001391 __ b(false_target);
1392 }
David Brazdil0debae72015-11-12 18:37:00 +00001393
1394 if (fallthrough_target.IsLinked()) {
1395 __ Bind(&fallthrough_target);
1396 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001397}
1398
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001399void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001400 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001401 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001402 Label* false_target) {
1403 HInstruction* cond = instruction->InputAt(condition_input_index);
1404
1405 if (true_target == nullptr && false_target == nullptr) {
1406 // Nothing to do. The code always falls through.
1407 return;
1408 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001409 // Constant condition, statically compared against "true" (integer value 1).
1410 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001411 if (true_target != nullptr) {
1412 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001413 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001414 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001415 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001416 if (false_target != nullptr) {
1417 __ b(false_target);
1418 }
1419 }
1420 return;
1421 }
1422
1423 // The following code generates these patterns:
1424 // (1) true_target == nullptr && false_target != nullptr
1425 // - opposite condition true => branch to false_target
1426 // (2) true_target != nullptr && false_target == nullptr
1427 // - condition true => branch to true_target
1428 // (3) true_target != nullptr && false_target != nullptr
1429 // - condition true => branch to true_target
1430 // - branch to false_target
1431 if (IsBooleanValueOrMaterializedCondition(cond)) {
1432 // Condition has been materialized, compare the output to 0.
1433 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1434 DCHECK(cond_val.IsRegister());
1435 if (true_target == nullptr) {
1436 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1437 } else {
1438 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001439 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001440 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001441 // Condition has not been materialized. Use its inputs as the comparison and
1442 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001443 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001444
1445 // If this is a long or FP comparison that has been folded into
1446 // the HCondition, generate the comparison directly.
1447 Primitive::Type type = condition->InputAt(0)->GetType();
1448 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1449 GenerateCompareTestAndBranch(condition, true_target, false_target);
1450 return;
1451 }
1452
1453 LocationSummary* locations = cond->GetLocations();
1454 DCHECK(locations->InAt(0).IsRegister());
1455 Register left = locations->InAt(0).AsRegister<Register>();
1456 Location right = locations->InAt(1);
1457 if (right.IsRegister()) {
1458 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001459 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001460 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001461 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001462 }
1463 if (true_target == nullptr) {
1464 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1465 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001466 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001467 }
Dave Allison20dfc792014-06-16 20:44:29 -07001468 }
David Brazdil0debae72015-11-12 18:37:00 +00001469
1470 // If neither branch falls through (case 3), the conditional branch to `true_target`
1471 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1472 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001473 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001474 }
1475}
1476
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001477void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001478 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1479 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001480 locations->SetInAt(0, Location::RequiresRegister());
1481 }
1482}
1483
1484void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001485 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1486 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1487 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1488 nullptr : codegen_->GetLabelOf(true_successor);
1489 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1490 nullptr : codegen_->GetLabelOf(false_successor);
1491 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001492}
1493
1494void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1495 LocationSummary* locations = new (GetGraph()->GetArena())
1496 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001497 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001498 locations->SetInAt(0, Location::RequiresRegister());
1499 }
1500}
1501
1502void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001503 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001504 GenerateTestAndBranch(deoptimize,
1505 /* condition_input_index */ 0,
1506 slow_path->GetEntryLabel(),
1507 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001508}
Dave Allison20dfc792014-06-16 20:44:29 -07001509
David Brazdil74eb1b22015-12-14 11:44:01 +00001510void LocationsBuilderARM::VisitSelect(HSelect* select) {
1511 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1512 if (Primitive::IsFloatingPointType(select->GetType())) {
1513 locations->SetInAt(0, Location::RequiresFpuRegister());
1514 locations->SetInAt(1, Location::RequiresFpuRegister());
1515 } else {
1516 locations->SetInAt(0, Location::RequiresRegister());
1517 locations->SetInAt(1, Location::RequiresRegister());
1518 }
1519 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1520 locations->SetInAt(2, Location::RequiresRegister());
1521 }
1522 locations->SetOut(Location::SameAsFirstInput());
1523}
1524
1525void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1526 LocationSummary* locations = select->GetLocations();
1527 Label false_target;
1528 GenerateTestAndBranch(select,
1529 /* condition_input_index */ 2,
1530 /* true_target */ nullptr,
1531 &false_target);
1532 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1533 __ Bind(&false_target);
1534}
1535
David Srbecky0cf44932015-12-09 14:09:59 +00001536void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1537 new (GetGraph()->GetArena()) LocationSummary(info);
1538}
1539
David Srbeckyd28f4a02016-03-14 17:14:24 +00001540void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
1541 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001542}
1543
1544void CodeGeneratorARM::GenerateNop() {
1545 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001546}
1547
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001548void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001549 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001550 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001551 // Handle the long/FP comparisons made in instruction simplification.
1552 switch (cond->InputAt(0)->GetType()) {
1553 case Primitive::kPrimLong:
1554 locations->SetInAt(0, Location::RequiresRegister());
1555 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001556 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001557 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1558 }
1559 break;
1560
1561 case Primitive::kPrimFloat:
1562 case Primitive::kPrimDouble:
1563 locations->SetInAt(0, Location::RequiresFpuRegister());
1564 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00001565 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001566 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1567 }
1568 break;
1569
1570 default:
1571 locations->SetInAt(0, Location::RequiresRegister());
1572 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001573 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001574 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1575 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001576 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001577}
1578
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001579void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001580 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001581 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001582 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001583
1584 LocationSummary* locations = cond->GetLocations();
1585 Location left = locations->InAt(0);
1586 Location right = locations->InAt(1);
1587 Register out = locations->Out().AsRegister<Register>();
1588 Label true_label, false_label;
1589
1590 switch (cond->InputAt(0)->GetType()) {
1591 default: {
1592 // Integer case.
1593 if (right.IsRegister()) {
1594 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1595 } else {
1596 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001597 __ CmpConstant(left.AsRegister<Register>(),
1598 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001599 }
Aart Bike9f37602015-10-09 11:15:55 -07001600 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001601 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001602 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001603 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001604 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001605 return;
1606 }
1607 case Primitive::kPrimLong:
1608 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1609 break;
1610 case Primitive::kPrimFloat:
1611 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1612 GenerateFPJumps(cond, &true_label, &false_label);
1613 break;
1614 case Primitive::kPrimDouble:
1615 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1616 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1617 GenerateFPJumps(cond, &true_label, &false_label);
1618 break;
1619 }
1620
1621 // Convert the jumps into the result.
1622 Label done_label;
1623
1624 // False case: result = 0.
1625 __ Bind(&false_label);
1626 __ LoadImmediate(out, 0);
1627 __ b(&done_label);
1628
1629 // True case: result = 1.
1630 __ Bind(&true_label);
1631 __ LoadImmediate(out, 1);
1632 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001633}
1634
1635void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001636 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001637}
1638
1639void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001640 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001641}
1642
1643void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001644 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001645}
1646
1647void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001648 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001649}
1650
1651void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001652 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001653}
1654
1655void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001656 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001657}
1658
1659void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001660 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001661}
1662
1663void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001664 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001665}
1666
1667void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001668 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001669}
1670
1671void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001672 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001673}
1674
1675void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001676 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001677}
1678
1679void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001680 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001681}
1682
Aart Bike9f37602015-10-09 11:15:55 -07001683void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001684 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001685}
1686
1687void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001688 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001689}
1690
1691void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001692 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001693}
1694
1695void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001696 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001697}
1698
1699void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001700 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001701}
1702
1703void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001704 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001705}
1706
1707void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001708 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001709}
1710
1711void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001712 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001713}
1714
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001715void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001716 LocationSummary* locations =
1717 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001718 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001719}
1720
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001721void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001722 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001723}
1724
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001725void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1726 LocationSummary* locations =
1727 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1728 locations->SetOut(Location::ConstantLocation(constant));
1729}
1730
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001731void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001732 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001733}
1734
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001735void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001736 LocationSummary* locations =
1737 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001738 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001739}
1740
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001741void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001742 // Will be generated at use site.
1743}
1744
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001745void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1746 LocationSummary* locations =
1747 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1748 locations->SetOut(Location::ConstantLocation(constant));
1749}
1750
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001751void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001752 // Will be generated at use site.
1753}
1754
1755void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1756 LocationSummary* locations =
1757 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1758 locations->SetOut(Location::ConstantLocation(constant));
1759}
1760
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001761void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001762 // Will be generated at use site.
1763}
1764
Calin Juravle27df7582015-04-17 19:12:31 +01001765void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1766 memory_barrier->SetLocations(nullptr);
1767}
1768
1769void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00001770 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01001771}
1772
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001773void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001774 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001775}
1776
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001777void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001778 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001779}
1780
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001781void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001782 LocationSummary* locations =
1783 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001784 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001785}
1786
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001787void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001788 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001789}
1790
Calin Juravle175dc732015-08-25 15:42:32 +01001791void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1792 // The trampoline uses the same calling convention as dex calling conventions,
1793 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1794 // the method_idx.
1795 HandleInvoke(invoke);
1796}
1797
1798void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1799 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1800}
1801
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001802void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001803 // Explicit clinit checks triggered by static invokes must have been pruned by
1804 // art::PrepareForRegisterAllocation.
1805 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001806
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001807 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001808 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001809 codegen_->GetInstructionSetFeatures());
1810 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001811 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1812 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1813 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001814 return;
1815 }
1816
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001817 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001818
1819 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1820 if (invoke->HasPcRelativeDexCache()) {
1821 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1822 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001823}
1824
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001825static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1826 if (invoke->GetLocations()->Intrinsified()) {
1827 IntrinsicCodeGeneratorARM intrinsic(codegen);
1828 intrinsic.Dispatch(invoke);
1829 return true;
1830 }
1831 return false;
1832}
1833
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001834void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001835 // Explicit clinit checks triggered by static invokes must have been pruned by
1836 // art::PrepareForRegisterAllocation.
1837 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001838
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001839 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1840 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001841 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001842
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001843 LocationSummary* locations = invoke->GetLocations();
1844 codegen_->GenerateStaticOrDirectCall(
1845 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001846 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001847}
1848
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001849void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001850 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001851 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001852}
1853
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001854void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001855 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001856 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001857 codegen_->GetInstructionSetFeatures());
1858 if (intrinsic.TryDispatch(invoke)) {
1859 return;
1860 }
1861
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001862 HandleInvoke(invoke);
1863}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001864
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001865void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001866 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1867 return;
1868 }
1869
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001870 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001871 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001872 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001873}
1874
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001875void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1876 HandleInvoke(invoke);
1877 // Add the hidden argument.
1878 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1879}
1880
1881void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1882 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001883 LocationSummary* locations = invoke->GetLocations();
1884 Register temp = locations->GetTemp(0).AsRegister<Register>();
1885 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001886 Location receiver = locations->InAt(0);
1887 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1888
Roland Levillain3b359c72015-11-17 19:35:12 +00001889 // Set the hidden argument. This is safe to do this here, as R12
1890 // won't be modified thereafter, before the `blx` (call) instruction.
1891 DCHECK_EQ(R12, hidden_reg);
1892 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001893
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001894 if (receiver.IsStackSlot()) {
1895 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00001896 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001897 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1898 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00001899 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00001900 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001901 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001902 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00001903 // Instead of simply (possibly) unpoisoning `temp` here, we should
1904 // emit a read barrier for the previous class reference load.
1905 // However this is not required in practice, as this is an
1906 // intermediate/temporary reference and because the current
1907 // concurrent copying collector keeps the from-space memory
1908 // intact/accessible until the end of the marking phase (the
1909 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01001910 __ MaybeUnpoisonHeapReference(temp);
Nelli Kimbadee982016-05-13 13:08:53 +03001911 __ LoadFromOffset(kLoadWord, temp, temp,
1912 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
1913 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity50706432016-06-14 11:31:04 -07001914 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001915 // temp = temp->GetImtEntryAt(method_offset);
Nelli Kimbadee982016-05-13 13:08:53 +03001916 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001917 uint32_t entry_point =
1918 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001919 // LR = temp->GetEntryPoint();
1920 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1921 // LR();
1922 __ blx(LR);
1923 DCHECK(!codegen_->IsLeafMethod());
1924 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1925}
1926
Roland Levillain88cb1752014-10-20 16:36:47 +01001927void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1928 LocationSummary* locations =
1929 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1930 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001931 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001932 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001933 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1934 break;
1935 }
1936 case Primitive::kPrimLong: {
1937 locations->SetInAt(0, Location::RequiresRegister());
1938 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001939 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001940 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001941
Roland Levillain88cb1752014-10-20 16:36:47 +01001942 case Primitive::kPrimFloat:
1943 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001944 locations->SetInAt(0, Location::RequiresFpuRegister());
1945 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001946 break;
1947
1948 default:
1949 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1950 }
1951}
1952
1953void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1954 LocationSummary* locations = neg->GetLocations();
1955 Location out = locations->Out();
1956 Location in = locations->InAt(0);
1957 switch (neg->GetResultType()) {
1958 case Primitive::kPrimInt:
1959 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001960 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001961 break;
1962
1963 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001964 DCHECK(in.IsRegisterPair());
1965 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1966 __ rsbs(out.AsRegisterPairLow<Register>(),
1967 in.AsRegisterPairLow<Register>(),
1968 ShifterOperand(0));
1969 // We cannot emit an RSC (Reverse Subtract with Carry)
1970 // instruction here, as it does not exist in the Thumb-2
1971 // instruction set. We use the following approach
1972 // using SBC and SUB instead.
1973 //
1974 // out.hi = -C
1975 __ sbc(out.AsRegisterPairHigh<Register>(),
1976 out.AsRegisterPairHigh<Register>(),
1977 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1978 // out.hi = out.hi - in.hi
1979 __ sub(out.AsRegisterPairHigh<Register>(),
1980 out.AsRegisterPairHigh<Register>(),
1981 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1982 break;
1983
Roland Levillain88cb1752014-10-20 16:36:47 +01001984 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001985 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001986 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001987 break;
1988
Roland Levillain88cb1752014-10-20 16:36:47 +01001989 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001990 DCHECK(in.IsFpuRegisterPair());
1991 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1992 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001993 break;
1994
1995 default:
1996 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1997 }
1998}
1999
Roland Levillaindff1f282014-11-05 14:15:05 +00002000void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002001 Primitive::Type result_type = conversion->GetResultType();
2002 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002003 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002004
Roland Levillain5b3ee562015-04-14 16:02:41 +01002005 // The float-to-long, double-to-long and long-to-float type conversions
2006 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002007 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002008 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2009 && result_type == Primitive::kPrimLong)
2010 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002011 ? LocationSummary::kCall
2012 : LocationSummary::kNoCall;
2013 LocationSummary* locations =
2014 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2015
David Brazdilb2bd1c52015-03-25 11:17:37 +00002016 // The Java language does not allow treating boolean as an integral type but
2017 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002018
Roland Levillaindff1f282014-11-05 14:15:05 +00002019 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002020 case Primitive::kPrimByte:
2021 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002022 case Primitive::kPrimLong:
2023 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002024 case Primitive::kPrimBoolean:
2025 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002026 case Primitive::kPrimShort:
2027 case Primitive::kPrimInt:
2028 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002029 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002030 locations->SetInAt(0, Location::RequiresRegister());
2031 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2032 break;
2033
2034 default:
2035 LOG(FATAL) << "Unexpected type conversion from " << input_type
2036 << " to " << result_type;
2037 }
2038 break;
2039
Roland Levillain01a8d712014-11-14 16:27:39 +00002040 case Primitive::kPrimShort:
2041 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002042 case Primitive::kPrimLong:
2043 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002044 case Primitive::kPrimBoolean:
2045 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002046 case Primitive::kPrimByte:
2047 case Primitive::kPrimInt:
2048 case Primitive::kPrimChar:
2049 // Processing a Dex `int-to-short' instruction.
2050 locations->SetInAt(0, Location::RequiresRegister());
2051 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2052 break;
2053
2054 default:
2055 LOG(FATAL) << "Unexpected type conversion from " << input_type
2056 << " to " << result_type;
2057 }
2058 break;
2059
Roland Levillain946e1432014-11-11 17:35:19 +00002060 case Primitive::kPrimInt:
2061 switch (input_type) {
2062 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002063 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002064 locations->SetInAt(0, Location::Any());
2065 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2066 break;
2067
2068 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002069 // Processing a Dex `float-to-int' instruction.
2070 locations->SetInAt(0, Location::RequiresFpuRegister());
2071 locations->SetOut(Location::RequiresRegister());
2072 locations->AddTemp(Location::RequiresFpuRegister());
2073 break;
2074
Roland Levillain946e1432014-11-11 17:35:19 +00002075 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002076 // Processing a Dex `double-to-int' instruction.
2077 locations->SetInAt(0, Location::RequiresFpuRegister());
2078 locations->SetOut(Location::RequiresRegister());
2079 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002080 break;
2081
2082 default:
2083 LOG(FATAL) << "Unexpected type conversion from " << input_type
2084 << " to " << result_type;
2085 }
2086 break;
2087
Roland Levillaindff1f282014-11-05 14:15:05 +00002088 case Primitive::kPrimLong:
2089 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002090 case Primitive::kPrimBoolean:
2091 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002092 case Primitive::kPrimByte:
2093 case Primitive::kPrimShort:
2094 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002095 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002096 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002097 locations->SetInAt(0, Location::RequiresRegister());
2098 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2099 break;
2100
Roland Levillain624279f2014-12-04 11:54:28 +00002101 case Primitive::kPrimFloat: {
2102 // Processing a Dex `float-to-long' instruction.
2103 InvokeRuntimeCallingConvention calling_convention;
2104 locations->SetInAt(0, Location::FpuRegisterLocation(
2105 calling_convention.GetFpuRegisterAt(0)));
2106 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2107 break;
2108 }
2109
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002110 case Primitive::kPrimDouble: {
2111 // Processing a Dex `double-to-long' instruction.
2112 InvokeRuntimeCallingConvention calling_convention;
2113 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2114 calling_convention.GetFpuRegisterAt(0),
2115 calling_convention.GetFpuRegisterAt(1)));
2116 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002117 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002118 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002119
2120 default:
2121 LOG(FATAL) << "Unexpected type conversion from " << input_type
2122 << " to " << result_type;
2123 }
2124 break;
2125
Roland Levillain981e4542014-11-14 11:47:14 +00002126 case Primitive::kPrimChar:
2127 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002128 case Primitive::kPrimLong:
2129 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002130 case Primitive::kPrimBoolean:
2131 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002132 case Primitive::kPrimByte:
2133 case Primitive::kPrimShort:
2134 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002135 // Processing a Dex `int-to-char' instruction.
2136 locations->SetInAt(0, Location::RequiresRegister());
2137 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2138 break;
2139
2140 default:
2141 LOG(FATAL) << "Unexpected type conversion from " << input_type
2142 << " to " << result_type;
2143 }
2144 break;
2145
Roland Levillaindff1f282014-11-05 14:15:05 +00002146 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002147 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002148 case Primitive::kPrimBoolean:
2149 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002150 case Primitive::kPrimByte:
2151 case Primitive::kPrimShort:
2152 case Primitive::kPrimInt:
2153 case Primitive::kPrimChar:
2154 // Processing a Dex `int-to-float' instruction.
2155 locations->SetInAt(0, Location::RequiresRegister());
2156 locations->SetOut(Location::RequiresFpuRegister());
2157 break;
2158
Roland Levillain5b3ee562015-04-14 16:02:41 +01002159 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002160 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002161 InvokeRuntimeCallingConvention calling_convention;
2162 locations->SetInAt(0, Location::RegisterPairLocation(
2163 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2164 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002165 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002166 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002167
Roland Levillaincff13742014-11-17 14:32:17 +00002168 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002169 // Processing a Dex `double-to-float' instruction.
2170 locations->SetInAt(0, Location::RequiresFpuRegister());
2171 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002172 break;
2173
2174 default:
2175 LOG(FATAL) << "Unexpected type conversion from " << input_type
2176 << " to " << result_type;
2177 };
2178 break;
2179
Roland Levillaindff1f282014-11-05 14:15:05 +00002180 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002181 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002182 case Primitive::kPrimBoolean:
2183 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002184 case Primitive::kPrimByte:
2185 case Primitive::kPrimShort:
2186 case Primitive::kPrimInt:
2187 case Primitive::kPrimChar:
2188 // Processing a Dex `int-to-double' instruction.
2189 locations->SetInAt(0, Location::RequiresRegister());
2190 locations->SetOut(Location::RequiresFpuRegister());
2191 break;
2192
2193 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002194 // Processing a Dex `long-to-double' instruction.
2195 locations->SetInAt(0, Location::RequiresRegister());
2196 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002197 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002198 locations->AddTemp(Location::RequiresFpuRegister());
2199 break;
2200
Roland Levillaincff13742014-11-17 14:32:17 +00002201 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002202 // Processing a Dex `float-to-double' instruction.
2203 locations->SetInAt(0, Location::RequiresFpuRegister());
2204 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002205 break;
2206
2207 default:
2208 LOG(FATAL) << "Unexpected type conversion from " << input_type
2209 << " to " << result_type;
2210 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002211 break;
2212
2213 default:
2214 LOG(FATAL) << "Unexpected type conversion from " << input_type
2215 << " to " << result_type;
2216 }
2217}
2218
2219void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2220 LocationSummary* locations = conversion->GetLocations();
2221 Location out = locations->Out();
2222 Location in = locations->InAt(0);
2223 Primitive::Type result_type = conversion->GetResultType();
2224 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002225 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002226 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002227 case Primitive::kPrimByte:
2228 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002229 case Primitive::kPrimLong:
2230 // Type conversion from long to byte is a result of code transformations.
2231 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2232 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002233 case Primitive::kPrimBoolean:
2234 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002235 case Primitive::kPrimShort:
2236 case Primitive::kPrimInt:
2237 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002238 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002239 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002240 break;
2241
2242 default:
2243 LOG(FATAL) << "Unexpected type conversion from " << input_type
2244 << " to " << result_type;
2245 }
2246 break;
2247
Roland Levillain01a8d712014-11-14 16:27:39 +00002248 case Primitive::kPrimShort:
2249 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002250 case Primitive::kPrimLong:
2251 // Type conversion from long to short is a result of code transformations.
2252 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2253 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002254 case Primitive::kPrimBoolean:
2255 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002256 case Primitive::kPrimByte:
2257 case Primitive::kPrimInt:
2258 case Primitive::kPrimChar:
2259 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002260 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002261 break;
2262
2263 default:
2264 LOG(FATAL) << "Unexpected type conversion from " << input_type
2265 << " to " << result_type;
2266 }
2267 break;
2268
Roland Levillain946e1432014-11-11 17:35:19 +00002269 case Primitive::kPrimInt:
2270 switch (input_type) {
2271 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002272 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002273 DCHECK(out.IsRegister());
2274 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002275 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002276 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002277 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002278 } else {
2279 DCHECK(in.IsConstant());
2280 DCHECK(in.GetConstant()->IsLongConstant());
2281 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002282 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002283 }
2284 break;
2285
Roland Levillain3f8f9362014-12-02 17:45:01 +00002286 case Primitive::kPrimFloat: {
2287 // Processing a Dex `float-to-int' instruction.
2288 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2289 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2290 __ vcvtis(temp, temp);
2291 __ vmovrs(out.AsRegister<Register>(), temp);
2292 break;
2293 }
2294
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002295 case Primitive::kPrimDouble: {
2296 // Processing a Dex `double-to-int' instruction.
2297 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2298 DRegister temp_d = FromLowSToD(temp_s);
2299 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2300 __ vcvtid(temp_s, temp_d);
2301 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002302 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002303 }
Roland Levillain946e1432014-11-11 17:35:19 +00002304
2305 default:
2306 LOG(FATAL) << "Unexpected type conversion from " << input_type
2307 << " to " << result_type;
2308 }
2309 break;
2310
Roland Levillaindff1f282014-11-05 14:15:05 +00002311 case Primitive::kPrimLong:
2312 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002313 case Primitive::kPrimBoolean:
2314 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002315 case Primitive::kPrimByte:
2316 case Primitive::kPrimShort:
2317 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002318 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002319 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002320 DCHECK(out.IsRegisterPair());
2321 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002322 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002323 // Sign extension.
2324 __ Asr(out.AsRegisterPairHigh<Register>(),
2325 out.AsRegisterPairLow<Register>(),
2326 31);
2327 break;
2328
2329 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002330 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002331 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2332 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002333 conversion->GetDexPc(),
2334 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002335 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002336 break;
2337
Roland Levillaindff1f282014-11-05 14:15:05 +00002338 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002339 // Processing a Dex `double-to-long' instruction.
2340 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2341 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002342 conversion->GetDexPc(),
2343 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002344 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002345 break;
2346
2347 default:
2348 LOG(FATAL) << "Unexpected type conversion from " << input_type
2349 << " to " << result_type;
2350 }
2351 break;
2352
Roland Levillain981e4542014-11-14 11:47:14 +00002353 case Primitive::kPrimChar:
2354 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002355 case Primitive::kPrimLong:
2356 // Type conversion from long to char is a result of code transformations.
2357 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2358 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002359 case Primitive::kPrimBoolean:
2360 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002361 case Primitive::kPrimByte:
2362 case Primitive::kPrimShort:
2363 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002364 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002365 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002366 break;
2367
2368 default:
2369 LOG(FATAL) << "Unexpected type conversion from " << input_type
2370 << " to " << result_type;
2371 }
2372 break;
2373
Roland Levillaindff1f282014-11-05 14:15:05 +00002374 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002375 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002376 case Primitive::kPrimBoolean:
2377 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002378 case Primitive::kPrimByte:
2379 case Primitive::kPrimShort:
2380 case Primitive::kPrimInt:
2381 case Primitive::kPrimChar: {
2382 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002383 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2384 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002385 break;
2386 }
2387
Roland Levillain5b3ee562015-04-14 16:02:41 +01002388 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002389 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002390 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2391 conversion,
2392 conversion->GetDexPc(),
2393 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002394 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002395 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002396
Roland Levillaincff13742014-11-17 14:32:17 +00002397 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002398 // Processing a Dex `double-to-float' instruction.
2399 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2400 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002401 break;
2402
2403 default:
2404 LOG(FATAL) << "Unexpected type conversion from " << input_type
2405 << " to " << result_type;
2406 };
2407 break;
2408
Roland Levillaindff1f282014-11-05 14:15:05 +00002409 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002410 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002411 case Primitive::kPrimBoolean:
2412 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002413 case Primitive::kPrimByte:
2414 case Primitive::kPrimShort:
2415 case Primitive::kPrimInt:
2416 case Primitive::kPrimChar: {
2417 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002418 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002419 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2420 out.AsFpuRegisterPairLow<SRegister>());
2421 break;
2422 }
2423
Roland Levillain647b9ed2014-11-27 12:06:00 +00002424 case Primitive::kPrimLong: {
2425 // Processing a Dex `long-to-double' instruction.
2426 Register low = in.AsRegisterPairLow<Register>();
2427 Register high = in.AsRegisterPairHigh<Register>();
2428 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2429 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002430 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002431 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002432 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2433 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002434
Roland Levillain682393c2015-04-14 15:57:52 +01002435 // temp_d = int-to-double(high)
2436 __ vmovsr(temp_s, high);
2437 __ vcvtdi(temp_d, temp_s);
2438 // constant_d = k2Pow32EncodingForDouble
2439 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2440 // out_d = unsigned-to-double(low)
2441 __ vmovsr(out_s, low);
2442 __ vcvtdu(out_d, out_s);
2443 // out_d += temp_d * constant_d
2444 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002445 break;
2446 }
2447
Roland Levillaincff13742014-11-17 14:32:17 +00002448 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002449 // Processing a Dex `float-to-double' instruction.
2450 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2451 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002452 break;
2453
2454 default:
2455 LOG(FATAL) << "Unexpected type conversion from " << input_type
2456 << " to " << result_type;
2457 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002458 break;
2459
2460 default:
2461 LOG(FATAL) << "Unexpected type conversion from " << input_type
2462 << " to " << result_type;
2463 }
2464}
2465
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002466void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002467 LocationSummary* locations =
2468 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002469 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002470 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002471 locations->SetInAt(0, Location::RequiresRegister());
2472 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002473 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2474 break;
2475 }
2476
2477 case Primitive::kPrimLong: {
2478 locations->SetInAt(0, Location::RequiresRegister());
2479 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002480 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002481 break;
2482 }
2483
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002484 case Primitive::kPrimFloat:
2485 case Primitive::kPrimDouble: {
2486 locations->SetInAt(0, Location::RequiresFpuRegister());
2487 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002488 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002489 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002490 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002491
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002492 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002493 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002494 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002495}
2496
2497void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2498 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002499 Location out = locations->Out();
2500 Location first = locations->InAt(0);
2501 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002502 switch (add->GetResultType()) {
2503 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002504 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002505 __ add(out.AsRegister<Register>(),
2506 first.AsRegister<Register>(),
2507 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002508 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002509 __ AddConstant(out.AsRegister<Register>(),
2510 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002511 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002512 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002513 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002514
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002515 case Primitive::kPrimLong: {
2516 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002517 __ adds(out.AsRegisterPairLow<Register>(),
2518 first.AsRegisterPairLow<Register>(),
2519 ShifterOperand(second.AsRegisterPairLow<Register>()));
2520 __ adc(out.AsRegisterPairHigh<Register>(),
2521 first.AsRegisterPairHigh<Register>(),
2522 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002523 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002524 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002525
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002526 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002527 __ vadds(out.AsFpuRegister<SRegister>(),
2528 first.AsFpuRegister<SRegister>(),
2529 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002530 break;
2531
2532 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002533 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2534 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2535 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002536 break;
2537
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002538 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002539 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002540 }
2541}
2542
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002543void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002544 LocationSummary* locations =
2545 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002546 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002547 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002548 locations->SetInAt(0, Location::RequiresRegister());
2549 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002550 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2551 break;
2552 }
2553
2554 case Primitive::kPrimLong: {
2555 locations->SetInAt(0, Location::RequiresRegister());
2556 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002557 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002558 break;
2559 }
Calin Juravle11351682014-10-23 15:38:15 +01002560 case Primitive::kPrimFloat:
2561 case Primitive::kPrimDouble: {
2562 locations->SetInAt(0, Location::RequiresFpuRegister());
2563 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002564 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002565 break;
Calin Juravle11351682014-10-23 15:38:15 +01002566 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002567 default:
Calin Juravle11351682014-10-23 15:38:15 +01002568 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002569 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002570}
2571
2572void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2573 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002574 Location out = locations->Out();
2575 Location first = locations->InAt(0);
2576 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002577 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002578 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002579 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002580 __ sub(out.AsRegister<Register>(),
2581 first.AsRegister<Register>(),
2582 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002583 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002584 __ AddConstant(out.AsRegister<Register>(),
2585 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002586 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002587 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002588 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002589 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002590
Calin Juravle11351682014-10-23 15:38:15 +01002591 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002592 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002593 __ subs(out.AsRegisterPairLow<Register>(),
2594 first.AsRegisterPairLow<Register>(),
2595 ShifterOperand(second.AsRegisterPairLow<Register>()));
2596 __ sbc(out.AsRegisterPairHigh<Register>(),
2597 first.AsRegisterPairHigh<Register>(),
2598 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002599 break;
Calin Juravle11351682014-10-23 15:38:15 +01002600 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002601
Calin Juravle11351682014-10-23 15:38:15 +01002602 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002603 __ vsubs(out.AsFpuRegister<SRegister>(),
2604 first.AsFpuRegister<SRegister>(),
2605 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002606 break;
Calin Juravle11351682014-10-23 15:38:15 +01002607 }
2608
2609 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002610 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2611 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2612 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002613 break;
2614 }
2615
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002616
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002617 default:
Calin Juravle11351682014-10-23 15:38:15 +01002618 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002619 }
2620}
2621
Calin Juravle34bacdf2014-10-07 20:23:36 +01002622void LocationsBuilderARM::VisitMul(HMul* mul) {
2623 LocationSummary* locations =
2624 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2625 switch (mul->GetResultType()) {
2626 case Primitive::kPrimInt:
2627 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002628 locations->SetInAt(0, Location::RequiresRegister());
2629 locations->SetInAt(1, Location::RequiresRegister());
2630 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002631 break;
2632 }
2633
Calin Juravleb5bfa962014-10-21 18:02:24 +01002634 case Primitive::kPrimFloat:
2635 case Primitive::kPrimDouble: {
2636 locations->SetInAt(0, Location::RequiresFpuRegister());
2637 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002638 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002639 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002640 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002641
2642 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002643 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002644 }
2645}
2646
2647void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2648 LocationSummary* locations = mul->GetLocations();
2649 Location out = locations->Out();
2650 Location first = locations->InAt(0);
2651 Location second = locations->InAt(1);
2652 switch (mul->GetResultType()) {
2653 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002654 __ mul(out.AsRegister<Register>(),
2655 first.AsRegister<Register>(),
2656 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002657 break;
2658 }
2659 case Primitive::kPrimLong: {
2660 Register out_hi = out.AsRegisterPairHigh<Register>();
2661 Register out_lo = out.AsRegisterPairLow<Register>();
2662 Register in1_hi = first.AsRegisterPairHigh<Register>();
2663 Register in1_lo = first.AsRegisterPairLow<Register>();
2664 Register in2_hi = second.AsRegisterPairHigh<Register>();
2665 Register in2_lo = second.AsRegisterPairLow<Register>();
2666
2667 // Extra checks to protect caused by the existence of R1_R2.
2668 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2669 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2670 DCHECK_NE(out_hi, in1_lo);
2671 DCHECK_NE(out_hi, in2_lo);
2672
2673 // input: in1 - 64 bits, in2 - 64 bits
2674 // output: out
2675 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2676 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2677 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2678
2679 // IP <- in1.lo * in2.hi
2680 __ mul(IP, in1_lo, in2_hi);
2681 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2682 __ mla(out_hi, in1_hi, in2_lo, IP);
2683 // out.lo <- (in1.lo * in2.lo)[31:0];
2684 __ umull(out_lo, IP, in1_lo, in2_lo);
2685 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2686 __ add(out_hi, out_hi, ShifterOperand(IP));
2687 break;
2688 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002689
2690 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002691 __ vmuls(out.AsFpuRegister<SRegister>(),
2692 first.AsFpuRegister<SRegister>(),
2693 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002694 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002695 }
2696
2697 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002698 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2699 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2700 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002701 break;
2702 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002703
2704 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002705 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002706 }
2707}
2708
Zheng Xuc6667102015-05-15 16:08:45 +08002709void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2710 DCHECK(instruction->IsDiv() || instruction->IsRem());
2711 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2712
2713 LocationSummary* locations = instruction->GetLocations();
2714 Location second = locations->InAt(1);
2715 DCHECK(second.IsConstant());
2716
2717 Register out = locations->Out().AsRegister<Register>();
2718 Register dividend = locations->InAt(0).AsRegister<Register>();
2719 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2720 DCHECK(imm == 1 || imm == -1);
2721
2722 if (instruction->IsRem()) {
2723 __ LoadImmediate(out, 0);
2724 } else {
2725 if (imm == 1) {
2726 __ Mov(out, dividend);
2727 } else {
2728 __ rsb(out, dividend, ShifterOperand(0));
2729 }
2730 }
2731}
2732
2733void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2734 DCHECK(instruction->IsDiv() || instruction->IsRem());
2735 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2736
2737 LocationSummary* locations = instruction->GetLocations();
2738 Location second = locations->InAt(1);
2739 DCHECK(second.IsConstant());
2740
2741 Register out = locations->Out().AsRegister<Register>();
2742 Register dividend = locations->InAt(0).AsRegister<Register>();
2743 Register temp = locations->GetTemp(0).AsRegister<Register>();
2744 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002745 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002746 int ctz_imm = CTZ(abs_imm);
2747
2748 if (ctz_imm == 1) {
2749 __ Lsr(temp, dividend, 32 - ctz_imm);
2750 } else {
2751 __ Asr(temp, dividend, 31);
2752 __ Lsr(temp, temp, 32 - ctz_imm);
2753 }
2754 __ add(out, temp, ShifterOperand(dividend));
2755
2756 if (instruction->IsDiv()) {
2757 __ Asr(out, out, ctz_imm);
2758 if (imm < 0) {
2759 __ rsb(out, out, ShifterOperand(0));
2760 }
2761 } else {
2762 __ ubfx(out, out, 0, ctz_imm);
2763 __ sub(out, out, ShifterOperand(temp));
2764 }
2765}
2766
2767void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2768 DCHECK(instruction->IsDiv() || instruction->IsRem());
2769 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2770
2771 LocationSummary* locations = instruction->GetLocations();
2772 Location second = locations->InAt(1);
2773 DCHECK(second.IsConstant());
2774
2775 Register out = locations->Out().AsRegister<Register>();
2776 Register dividend = locations->InAt(0).AsRegister<Register>();
2777 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2778 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2779 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2780
2781 int64_t magic;
2782 int shift;
2783 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2784
2785 __ LoadImmediate(temp1, magic);
2786 __ smull(temp2, temp1, dividend, temp1);
2787
2788 if (imm > 0 && magic < 0) {
2789 __ add(temp1, temp1, ShifterOperand(dividend));
2790 } else if (imm < 0 && magic > 0) {
2791 __ sub(temp1, temp1, ShifterOperand(dividend));
2792 }
2793
2794 if (shift != 0) {
2795 __ Asr(temp1, temp1, shift);
2796 }
2797
2798 if (instruction->IsDiv()) {
2799 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2800 } else {
2801 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2802 // TODO: Strength reduction for mls.
2803 __ LoadImmediate(temp2, imm);
2804 __ mls(out, temp1, temp2, dividend);
2805 }
2806}
2807
2808void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2809 DCHECK(instruction->IsDiv() || instruction->IsRem());
2810 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2811
2812 LocationSummary* locations = instruction->GetLocations();
2813 Location second = locations->InAt(1);
2814 DCHECK(second.IsConstant());
2815
2816 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2817 if (imm == 0) {
2818 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2819 } else if (imm == 1 || imm == -1) {
2820 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002821 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002822 DivRemByPowerOfTwo(instruction);
2823 } else {
2824 DCHECK(imm <= -2 || imm >= 2);
2825 GenerateDivRemWithAnyConstant(instruction);
2826 }
2827}
2828
Calin Juravle7c4954d2014-10-28 16:57:40 +00002829void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002830 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2831 if (div->GetResultType() == Primitive::kPrimLong) {
2832 // pLdiv runtime call.
2833 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002834 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2835 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002836 } else if (div->GetResultType() == Primitive::kPrimInt &&
2837 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2838 // pIdivmod runtime call.
2839 call_kind = LocationSummary::kCall;
2840 }
2841
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002842 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2843
Calin Juravle7c4954d2014-10-28 16:57:40 +00002844 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002845 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002846 if (div->InputAt(1)->IsConstant()) {
2847 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002848 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002849 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002850 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
2851 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002852 // No temp register required.
2853 } else {
2854 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002855 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002856 locations->AddTemp(Location::RequiresRegister());
2857 }
2858 }
2859 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002860 locations->SetInAt(0, Location::RequiresRegister());
2861 locations->SetInAt(1, Location::RequiresRegister());
2862 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2863 } else {
2864 InvokeRuntimeCallingConvention calling_convention;
2865 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2866 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2867 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2868 // we only need the former.
2869 locations->SetOut(Location::RegisterLocation(R0));
2870 }
Calin Juravled0d48522014-11-04 16:40:20 +00002871 break;
2872 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002873 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002874 InvokeRuntimeCallingConvention calling_convention;
2875 locations->SetInAt(0, Location::RegisterPairLocation(
2876 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2877 locations->SetInAt(1, Location::RegisterPairLocation(
2878 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002879 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002880 break;
2881 }
2882 case Primitive::kPrimFloat:
2883 case Primitive::kPrimDouble: {
2884 locations->SetInAt(0, Location::RequiresFpuRegister());
2885 locations->SetInAt(1, Location::RequiresFpuRegister());
2886 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2887 break;
2888 }
2889
2890 default:
2891 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2892 }
2893}
2894
2895void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2896 LocationSummary* locations = div->GetLocations();
2897 Location out = locations->Out();
2898 Location first = locations->InAt(0);
2899 Location second = locations->InAt(1);
2900
2901 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002902 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002903 if (second.IsConstant()) {
2904 GenerateDivRemConstantIntegral(div);
2905 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002906 __ sdiv(out.AsRegister<Register>(),
2907 first.AsRegister<Register>(),
2908 second.AsRegister<Register>());
2909 } else {
2910 InvokeRuntimeCallingConvention calling_convention;
2911 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2912 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2913 DCHECK_EQ(R0, out.AsRegister<Register>());
2914
2915 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002916 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002917 }
Calin Juravled0d48522014-11-04 16:40:20 +00002918 break;
2919 }
2920
Calin Juravle7c4954d2014-10-28 16:57:40 +00002921 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002922 InvokeRuntimeCallingConvention calling_convention;
2923 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2924 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2925 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2926 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2927 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002928 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002929
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002930 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002931 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002932 break;
2933 }
2934
2935 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002936 __ vdivs(out.AsFpuRegister<SRegister>(),
2937 first.AsFpuRegister<SRegister>(),
2938 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002939 break;
2940 }
2941
2942 case Primitive::kPrimDouble: {
2943 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2944 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2945 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2946 break;
2947 }
2948
2949 default:
2950 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2951 }
2952}
2953
Calin Juravlebacfec32014-11-14 15:54:36 +00002954void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002955 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002956
2957 // Most remainders are implemented in the runtime.
2958 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002959 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2960 // sdiv will be replaced by other instruction sequence.
2961 call_kind = LocationSummary::kNoCall;
2962 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2963 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002964 // Have hardware divide instruction for int, do it with three instructions.
2965 call_kind = LocationSummary::kNoCall;
2966 }
2967
Calin Juravlebacfec32014-11-14 15:54:36 +00002968 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2969
Calin Juravled2ec87d2014-12-08 14:24:46 +00002970 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002971 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002972 if (rem->InputAt(1)->IsConstant()) {
2973 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002974 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002975 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002976 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
2977 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002978 // No temp register required.
2979 } else {
2980 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002981 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002982 locations->AddTemp(Location::RequiresRegister());
2983 }
2984 }
2985 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002986 locations->SetInAt(0, Location::RequiresRegister());
2987 locations->SetInAt(1, Location::RequiresRegister());
2988 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2989 locations->AddTemp(Location::RequiresRegister());
2990 } else {
2991 InvokeRuntimeCallingConvention calling_convention;
2992 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2993 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2994 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2995 // we only need the latter.
2996 locations->SetOut(Location::RegisterLocation(R1));
2997 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002998 break;
2999 }
3000 case Primitive::kPrimLong: {
3001 InvokeRuntimeCallingConvention calling_convention;
3002 locations->SetInAt(0, Location::RegisterPairLocation(
3003 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3004 locations->SetInAt(1, Location::RegisterPairLocation(
3005 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3006 // The runtime helper puts the output in R2,R3.
3007 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3008 break;
3009 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003010 case Primitive::kPrimFloat: {
3011 InvokeRuntimeCallingConvention calling_convention;
3012 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3013 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3014 locations->SetOut(Location::FpuRegisterLocation(S0));
3015 break;
3016 }
3017
Calin Juravlebacfec32014-11-14 15:54:36 +00003018 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003019 InvokeRuntimeCallingConvention calling_convention;
3020 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3021 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3022 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3023 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3024 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003025 break;
3026 }
3027
3028 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003029 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003030 }
3031}
3032
3033void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3034 LocationSummary* locations = rem->GetLocations();
3035 Location out = locations->Out();
3036 Location first = locations->InAt(0);
3037 Location second = locations->InAt(1);
3038
Calin Juravled2ec87d2014-12-08 14:24:46 +00003039 Primitive::Type type = rem->GetResultType();
3040 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003041 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003042 if (second.IsConstant()) {
3043 GenerateDivRemConstantIntegral(rem);
3044 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003045 Register reg1 = first.AsRegister<Register>();
3046 Register reg2 = second.AsRegister<Register>();
3047 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003048
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003049 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003050 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003051 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003052 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003053 } else {
3054 InvokeRuntimeCallingConvention calling_convention;
3055 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3056 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3057 DCHECK_EQ(R1, out.AsRegister<Register>());
3058
3059 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003060 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003061 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003062 break;
3063 }
3064
3065 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003066 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003067 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003068 break;
3069 }
3070
Calin Juravled2ec87d2014-12-08 14:24:46 +00003071 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003072 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003073 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003074 break;
3075 }
3076
Calin Juravlebacfec32014-11-14 15:54:36 +00003077 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003078 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003079 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003080 break;
3081 }
3082
3083 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003084 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003085 }
3086}
3087
Calin Juravled0d48522014-11-04 16:40:20 +00003088void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003089 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3090 ? LocationSummary::kCallOnSlowPath
3091 : LocationSummary::kNoCall;
3092 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003093 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003094 if (instruction->HasUses()) {
3095 locations->SetOut(Location::SameAsFirstInput());
3096 }
3097}
3098
3099void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003100 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003101 codegen_->AddSlowPath(slow_path);
3102
3103 LocationSummary* locations = instruction->GetLocations();
3104 Location value = locations->InAt(0);
3105
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003106 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003107 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003108 case Primitive::kPrimByte:
3109 case Primitive::kPrimChar:
3110 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003111 case Primitive::kPrimInt: {
3112 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003113 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003114 } else {
3115 DCHECK(value.IsConstant()) << value;
3116 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3117 __ b(slow_path->GetEntryLabel());
3118 }
3119 }
3120 break;
3121 }
3122 case Primitive::kPrimLong: {
3123 if (value.IsRegisterPair()) {
3124 __ orrs(IP,
3125 value.AsRegisterPairLow<Register>(),
3126 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3127 __ b(slow_path->GetEntryLabel(), EQ);
3128 } else {
3129 DCHECK(value.IsConstant()) << value;
3130 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3131 __ b(slow_path->GetEntryLabel());
3132 }
3133 }
3134 break;
3135 default:
3136 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3137 }
3138 }
Calin Juravled0d48522014-11-04 16:40:20 +00003139}
3140
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003141void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3142 Register in = locations->InAt(0).AsRegister<Register>();
3143 Location rhs = locations->InAt(1);
3144 Register out = locations->Out().AsRegister<Register>();
3145
3146 if (rhs.IsConstant()) {
3147 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3148 // so map all rotations to a +ve. equivalent in that range.
3149 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3150 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3151 if (rot) {
3152 // Rotate, mapping left rotations to right equivalents if necessary.
3153 // (e.g. left by 2 bits == right by 30.)
3154 __ Ror(out, in, rot);
3155 } else if (out != in) {
3156 __ Mov(out, in);
3157 }
3158 } else {
3159 __ Ror(out, in, rhs.AsRegister<Register>());
3160 }
3161}
3162
3163// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3164// rotates by swapping input regs (effectively rotating by the first 32-bits of
3165// a larger rotation) or flipping direction (thus treating larger right/left
3166// rotations as sub-word sized rotations in the other direction) as appropriate.
3167void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3168 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3169 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3170 Location rhs = locations->InAt(1);
3171 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3172 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3173
3174 if (rhs.IsConstant()) {
3175 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3176 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003177 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003178 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3179 // logic below to a simple pair of binary orr.
3180 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3181 if (rot >= kArmBitsPerWord) {
3182 rot -= kArmBitsPerWord;
3183 std::swap(in_reg_hi, in_reg_lo);
3184 }
3185 // Rotate, or mov to out for zero or word size rotations.
3186 if (rot != 0u) {
3187 __ Lsr(out_reg_hi, in_reg_hi, rot);
3188 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3189 __ Lsr(out_reg_lo, in_reg_lo, rot);
3190 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3191 } else {
3192 __ Mov(out_reg_lo, in_reg_lo);
3193 __ Mov(out_reg_hi, in_reg_hi);
3194 }
3195 } else {
3196 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3197 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3198 Label end;
3199 Label shift_by_32_plus_shift_right;
3200
3201 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3202 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3203 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3204 __ b(&shift_by_32_plus_shift_right, CC);
3205
3206 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3207 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3208 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3209 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3210 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3211 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3212 __ Lsr(shift_left, in_reg_hi, shift_right);
3213 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3214 __ b(&end);
3215
3216 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3217 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3218 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3219 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3220 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3221 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3222 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3223 __ Lsl(shift_right, in_reg_hi, shift_left);
3224 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3225
3226 __ Bind(&end);
3227 }
3228}
Roland Levillain22c49222016-03-18 14:04:28 +00003229
3230void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003231 LocationSummary* locations =
3232 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3233 switch (ror->GetResultType()) {
3234 case Primitive::kPrimInt: {
3235 locations->SetInAt(0, Location::RequiresRegister());
3236 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3237 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3238 break;
3239 }
3240 case Primitive::kPrimLong: {
3241 locations->SetInAt(0, Location::RequiresRegister());
3242 if (ror->InputAt(1)->IsConstant()) {
3243 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3244 } else {
3245 locations->SetInAt(1, Location::RequiresRegister());
3246 locations->AddTemp(Location::RequiresRegister());
3247 locations->AddTemp(Location::RequiresRegister());
3248 }
3249 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3250 break;
3251 }
3252 default:
3253 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3254 }
3255}
3256
Roland Levillain22c49222016-03-18 14:04:28 +00003257void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003258 LocationSummary* locations = ror->GetLocations();
3259 Primitive::Type type = ror->GetResultType();
3260 switch (type) {
3261 case Primitive::kPrimInt: {
3262 HandleIntegerRotate(locations);
3263 break;
3264 }
3265 case Primitive::kPrimLong: {
3266 HandleLongRotate(locations);
3267 break;
3268 }
3269 default:
3270 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003271 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003272 }
3273}
3274
Calin Juravle9aec02f2014-11-18 23:06:35 +00003275void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3276 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3277
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003278 LocationSummary* locations =
3279 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003280
3281 switch (op->GetResultType()) {
3282 case Primitive::kPrimInt: {
3283 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003284 if (op->InputAt(1)->IsConstant()) {
3285 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3286 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3287 } else {
3288 locations->SetInAt(1, Location::RequiresRegister());
3289 // Make the output overlap, as it will be used to hold the masked
3290 // second input.
3291 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3292 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003293 break;
3294 }
3295 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003296 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003297 if (op->InputAt(1)->IsConstant()) {
3298 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3299 // For simplicity, use kOutputOverlap even though we only require that low registers
3300 // don't clash with high registers which the register allocator currently guarantees.
3301 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3302 } else {
3303 locations->SetInAt(1, Location::RequiresRegister());
3304 locations->AddTemp(Location::RequiresRegister());
3305 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3306 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003307 break;
3308 }
3309 default:
3310 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3311 }
3312}
3313
3314void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3315 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3316
3317 LocationSummary* locations = op->GetLocations();
3318 Location out = locations->Out();
3319 Location first = locations->InAt(0);
3320 Location second = locations->InAt(1);
3321
3322 Primitive::Type type = op->GetResultType();
3323 switch (type) {
3324 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003325 Register out_reg = out.AsRegister<Register>();
3326 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003327 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003328 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003329 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003330 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003331 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003332 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003333 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003334 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003335 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003336 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003337 }
3338 } else {
3339 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003340 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003341 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003342 __ Mov(out_reg, first_reg);
3343 } else if (op->IsShl()) {
3344 __ Lsl(out_reg, first_reg, shift_value);
3345 } else if (op->IsShr()) {
3346 __ Asr(out_reg, first_reg, shift_value);
3347 } else {
3348 __ Lsr(out_reg, first_reg, shift_value);
3349 }
3350 }
3351 break;
3352 }
3353 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003354 Register o_h = out.AsRegisterPairHigh<Register>();
3355 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003356
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003357 Register high = first.AsRegisterPairHigh<Register>();
3358 Register low = first.AsRegisterPairLow<Register>();
3359
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003360 if (second.IsRegister()) {
3361 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003362
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003363 Register second_reg = second.AsRegister<Register>();
3364
3365 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003366 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003367 // Shift the high part
3368 __ Lsl(o_h, high, o_l);
3369 // Shift the low part and `or` what overflew on the high part
3370 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3371 __ Lsr(temp, low, temp);
3372 __ orr(o_h, o_h, ShifterOperand(temp));
3373 // If the shift is > 32 bits, override the high part
3374 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3375 __ it(PL);
3376 __ Lsl(o_h, low, temp, PL);
3377 // Shift the low part
3378 __ Lsl(o_l, low, o_l);
3379 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003380 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003381 // Shift the low part
3382 __ Lsr(o_l, low, o_h);
3383 // Shift the high part and `or` what underflew on the low part
3384 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3385 __ Lsl(temp, high, temp);
3386 __ orr(o_l, o_l, ShifterOperand(temp));
3387 // If the shift is > 32 bits, override the low part
3388 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3389 __ it(PL);
3390 __ Asr(o_l, high, temp, PL);
3391 // Shift the high part
3392 __ Asr(o_h, high, o_h);
3393 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003394 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003395 // same as Shr except we use `Lsr`s and not `Asr`s
3396 __ Lsr(o_l, low, o_h);
3397 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3398 __ Lsl(temp, high, temp);
3399 __ orr(o_l, o_l, ShifterOperand(temp));
3400 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3401 __ it(PL);
3402 __ Lsr(o_l, high, temp, PL);
3403 __ Lsr(o_h, high, o_h);
3404 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003405 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003406 // Register allocator doesn't create partial overlap.
3407 DCHECK_NE(o_l, high);
3408 DCHECK_NE(o_h, low);
3409 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003410 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003411 if (shift_value > 32) {
3412 if (op->IsShl()) {
3413 __ Lsl(o_h, low, shift_value - 32);
3414 __ LoadImmediate(o_l, 0);
3415 } else if (op->IsShr()) {
3416 __ Asr(o_l, high, shift_value - 32);
3417 __ Asr(o_h, high, 31);
3418 } else {
3419 __ Lsr(o_l, high, shift_value - 32);
3420 __ LoadImmediate(o_h, 0);
3421 }
3422 } else if (shift_value == 32) {
3423 if (op->IsShl()) {
3424 __ mov(o_h, ShifterOperand(low));
3425 __ LoadImmediate(o_l, 0);
3426 } else if (op->IsShr()) {
3427 __ mov(o_l, ShifterOperand(high));
3428 __ Asr(o_h, high, 31);
3429 } else {
3430 __ mov(o_l, ShifterOperand(high));
3431 __ LoadImmediate(o_h, 0);
3432 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003433 } else if (shift_value == 1) {
3434 if (op->IsShl()) {
3435 __ Lsls(o_l, low, 1);
3436 __ adc(o_h, high, ShifterOperand(high));
3437 } else if (op->IsShr()) {
3438 __ Asrs(o_h, high, 1);
3439 __ Rrx(o_l, low);
3440 } else {
3441 __ Lsrs(o_h, high, 1);
3442 __ Rrx(o_l, low);
3443 }
3444 } else {
3445 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003446 if (op->IsShl()) {
3447 __ Lsl(o_h, high, shift_value);
3448 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3449 __ Lsl(o_l, low, shift_value);
3450 } else if (op->IsShr()) {
3451 __ Lsr(o_l, low, shift_value);
3452 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3453 __ Asr(o_h, high, shift_value);
3454 } else {
3455 __ Lsr(o_l, low, shift_value);
3456 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3457 __ Lsr(o_h, high, shift_value);
3458 }
3459 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003460 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003461 break;
3462 }
3463 default:
3464 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003465 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003466 }
3467}
3468
3469void LocationsBuilderARM::VisitShl(HShl* shl) {
3470 HandleShift(shl);
3471}
3472
3473void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3474 HandleShift(shl);
3475}
3476
3477void LocationsBuilderARM::VisitShr(HShr* shr) {
3478 HandleShift(shr);
3479}
3480
3481void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3482 HandleShift(shr);
3483}
3484
3485void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3486 HandleShift(ushr);
3487}
3488
3489void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3490 HandleShift(ushr);
3491}
3492
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003493void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003494 LocationSummary* locations =
3495 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
David Brazdil6de19382016-01-08 17:37:10 +00003496 if (instruction->IsStringAlloc()) {
3497 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3498 } else {
3499 InvokeRuntimeCallingConvention calling_convention;
3500 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3501 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3502 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003503 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003504}
3505
3506void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003507 // Note: if heap poisoning is enabled, the entry point takes cares
3508 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003509 if (instruction->IsStringAlloc()) {
3510 // String is allocated through StringFactory. Call NewEmptyString entry point.
3511 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
3512 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
3513 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3514 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3515 __ blx(LR);
3516 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3517 } else {
3518 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3519 instruction,
3520 instruction->GetDexPc(),
3521 nullptr);
3522 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3523 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003524}
3525
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003526void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3527 LocationSummary* locations =
3528 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3529 InvokeRuntimeCallingConvention calling_convention;
3530 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003531 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003532 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003533 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003534}
3535
3536void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3537 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003538 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003539 // Note: if heap poisoning is enabled, the entry point takes cares
3540 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003541 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003542 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003543 instruction->GetDexPc(),
3544 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003545 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003546}
3547
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003548void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003549 LocationSummary* locations =
3550 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003551 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3552 if (location.IsStackSlot()) {
3553 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3554 } else if (location.IsDoubleStackSlot()) {
3555 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003556 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003557 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003558}
3559
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003560void InstructionCodeGeneratorARM::VisitParameterValue(
3561 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003562 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003563}
3564
3565void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3566 LocationSummary* locations =
3567 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3568 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3569}
3570
3571void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3572 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003573}
3574
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003575void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003576 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003577 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003578 locations->SetInAt(0, Location::RequiresRegister());
3579 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003580}
3581
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003582void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3583 LocationSummary* locations = not_->GetLocations();
3584 Location out = locations->Out();
3585 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003586 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003587 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003588 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003589 break;
3590
3591 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003592 __ mvn(out.AsRegisterPairLow<Register>(),
3593 ShifterOperand(in.AsRegisterPairLow<Register>()));
3594 __ mvn(out.AsRegisterPairHigh<Register>(),
3595 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003596 break;
3597
3598 default:
3599 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3600 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003601}
3602
David Brazdil66d126e2015-04-03 16:02:44 +01003603void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3604 LocationSummary* locations =
3605 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3606 locations->SetInAt(0, Location::RequiresRegister());
3607 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3608}
3609
3610void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003611 LocationSummary* locations = bool_not->GetLocations();
3612 Location out = locations->Out();
3613 Location in = locations->InAt(0);
3614 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3615}
3616
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003617void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003618 LocationSummary* locations =
3619 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003620 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003621 case Primitive::kPrimBoolean:
3622 case Primitive::kPrimByte:
3623 case Primitive::kPrimShort:
3624 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003625 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00003626 case Primitive::kPrimLong: {
3627 locations->SetInAt(0, Location::RequiresRegister());
3628 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003629 // Output overlaps because it is written before doing the low comparison.
3630 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003631 break;
3632 }
3633 case Primitive::kPrimFloat:
3634 case Primitive::kPrimDouble: {
3635 locations->SetInAt(0, Location::RequiresFpuRegister());
3636 locations->SetInAt(1, Location::RequiresFpuRegister());
3637 locations->SetOut(Location::RequiresRegister());
3638 break;
3639 }
3640 default:
3641 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3642 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003643}
3644
3645void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003646 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003647 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003648 Location left = locations->InAt(0);
3649 Location right = locations->InAt(1);
3650
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003651 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003652 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00003653 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00003654 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003655 case Primitive::kPrimBoolean:
3656 case Primitive::kPrimByte:
3657 case Primitive::kPrimShort:
3658 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003659 case Primitive::kPrimInt: {
3660 __ LoadImmediate(out, 0);
3661 __ cmp(left.AsRegister<Register>(),
3662 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
3663 less_cond = LT;
3664 break;
3665 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003666 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003667 __ cmp(left.AsRegisterPairHigh<Register>(),
3668 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003669 __ b(&less, LT);
3670 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003671 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003672 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003673 __ cmp(left.AsRegisterPairLow<Register>(),
3674 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003675 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00003676 break;
3677 }
3678 case Primitive::kPrimFloat:
3679 case Primitive::kPrimDouble: {
3680 __ LoadImmediate(out, 0);
3681 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003682 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003683 } else {
3684 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3685 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3686 }
3687 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003688 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003689 break;
3690 }
3691 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003692 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00003693 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003694 }
Aart Bika19616e2016-02-01 18:57:58 -08003695
Calin Juravleddb7df22014-11-25 20:56:51 +00003696 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00003697 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00003698
3699 __ Bind(&greater);
3700 __ LoadImmediate(out, 1);
3701 __ b(&done);
3702
3703 __ Bind(&less);
3704 __ LoadImmediate(out, -1);
3705
3706 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003707}
3708
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003709void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003710 LocationSummary* locations =
3711 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01003712 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003713 locations->SetInAt(i, Location::Any());
3714 }
3715 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003716}
3717
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003718void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003719 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003720}
3721
Roland Levillainc9285912015-12-18 10:38:42 +00003722void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3723 // TODO (ported from quick): revisit ARM barrier kinds.
3724 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00003725 switch (kind) {
3726 case MemBarrierKind::kAnyStore:
3727 case MemBarrierKind::kLoadAny:
3728 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003729 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003730 break;
3731 }
3732 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003733 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003734 break;
3735 }
3736 default:
3737 LOG(FATAL) << "Unexpected memory barrier " << kind;
3738 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003739 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003740}
3741
3742void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3743 uint32_t offset,
3744 Register out_lo,
3745 Register out_hi) {
3746 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003747 // Ensure `out_lo` is different from `addr`, so that loading
3748 // `offset` into `out_lo` does not clutter `addr`.
3749 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003750 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003751 __ add(IP, addr, ShifterOperand(out_lo));
3752 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003753 }
3754 __ ldrexd(out_lo, out_hi, addr);
3755}
3756
3757void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3758 uint32_t offset,
3759 Register value_lo,
3760 Register value_hi,
3761 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003762 Register temp2,
3763 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003764 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003765 if (offset != 0) {
3766 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003767 __ add(IP, addr, ShifterOperand(temp1));
3768 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003769 }
3770 __ Bind(&fail);
3771 // We need a load followed by store. (The address used in a STREX instruction must
3772 // be the same as the address in the most recently executed LDREX instruction.)
3773 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003774 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003775 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003776 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003777}
3778
3779void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3780 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3781
Nicolas Geoffray39468442014-09-02 15:17:15 +01003782 LocationSummary* locations =
3783 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003784 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003785
Calin Juravle52c48962014-12-16 17:02:57 +00003786 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003787 if (Primitive::IsFloatingPointType(field_type)) {
3788 locations->SetInAt(1, Location::RequiresFpuRegister());
3789 } else {
3790 locations->SetInAt(1, Location::RequiresRegister());
3791 }
3792
Calin Juravle52c48962014-12-16 17:02:57 +00003793 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003794 bool generate_volatile = field_info.IsVolatile()
3795 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003796 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003797 bool needs_write_barrier =
3798 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003799 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003800 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003801 if (needs_write_barrier) {
3802 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003803 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003804 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003805 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003806 // - registers need to be consecutive
3807 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003808 // We don't test for ARM yet, and the assertion makes sure that we
3809 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003810 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3811
3812 locations->AddTemp(Location::RequiresRegister());
3813 locations->AddTemp(Location::RequiresRegister());
3814 if (field_type == Primitive::kPrimDouble) {
3815 // For doubles we need two more registers to copy the value.
3816 locations->AddTemp(Location::RegisterLocation(R2));
3817 locations->AddTemp(Location::RegisterLocation(R3));
3818 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003819 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003820}
3821
Calin Juravle52c48962014-12-16 17:02:57 +00003822void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003823 const FieldInfo& field_info,
3824 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003825 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3826
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003827 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003828 Register base = locations->InAt(0).AsRegister<Register>();
3829 Location value = locations->InAt(1);
3830
3831 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003832 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003833 Primitive::Type field_type = field_info.GetFieldType();
3834 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003835 bool needs_write_barrier =
3836 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003837
3838 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003839 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00003840 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003841
3842 switch (field_type) {
3843 case Primitive::kPrimBoolean:
3844 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003845 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003846 break;
3847 }
3848
3849 case Primitive::kPrimShort:
3850 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003851 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003852 break;
3853 }
3854
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003855 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003856 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003857 if (kPoisonHeapReferences && needs_write_barrier) {
3858 // Note that in the case where `value` is a null reference,
3859 // we do not enter this block, as a null reference does not
3860 // need poisoning.
3861 DCHECK_EQ(field_type, Primitive::kPrimNot);
3862 Register temp = locations->GetTemp(0).AsRegister<Register>();
3863 __ Mov(temp, value.AsRegister<Register>());
3864 __ PoisonHeapReference(temp);
3865 __ StoreToOffset(kStoreWord, temp, base, offset);
3866 } else {
3867 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3868 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003869 break;
3870 }
3871
3872 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003873 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003874 GenerateWideAtomicStore(base, offset,
3875 value.AsRegisterPairLow<Register>(),
3876 value.AsRegisterPairHigh<Register>(),
3877 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003878 locations->GetTemp(1).AsRegister<Register>(),
3879 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003880 } else {
3881 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003882 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003883 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003884 break;
3885 }
3886
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003887 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003888 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003889 break;
3890 }
3891
3892 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003893 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003894 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003895 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3896 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3897
3898 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3899
3900 GenerateWideAtomicStore(base, offset,
3901 value_reg_lo,
3902 value_reg_hi,
3903 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003904 locations->GetTemp(3).AsRegister<Register>(),
3905 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003906 } else {
3907 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003908 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003909 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003910 break;
3911 }
3912
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003913 case Primitive::kPrimVoid:
3914 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003915 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003916 }
Calin Juravle52c48962014-12-16 17:02:57 +00003917
Calin Juravle77520bc2015-01-12 18:45:46 +00003918 // Longs and doubles are handled in the switch.
3919 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3920 codegen_->MaybeRecordImplicitNullCheck(instruction);
3921 }
3922
3923 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3924 Register temp = locations->GetTemp(0).AsRegister<Register>();
3925 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003926 codegen_->MarkGCCard(
3927 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003928 }
3929
Calin Juravle52c48962014-12-16 17:02:57 +00003930 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003931 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00003932 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003933}
3934
Calin Juravle52c48962014-12-16 17:02:57 +00003935void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3936 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003937
3938 bool object_field_get_with_read_barrier =
3939 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003940 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003941 new (GetGraph()->GetArena()) LocationSummary(instruction,
3942 object_field_get_with_read_barrier ?
3943 LocationSummary::kCallOnSlowPath :
3944 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003945 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003946
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003947 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003948 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003949 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00003950 // The output overlaps in case of volatile long: we don't want the
3951 // code generated by GenerateWideAtomicLoad to overwrite the
3952 // object's location. Likewise, in the case of an object field get
3953 // with read barriers enabled, we do not want the load to overwrite
3954 // the object's location, as we need it to emit the read barrier.
3955 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
3956 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003957
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003958 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3959 locations->SetOut(Location::RequiresFpuRegister());
3960 } else {
3961 locations->SetOut(Location::RequiresRegister(),
3962 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3963 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003964 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00003965 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003966 // - registers need to be consecutive
3967 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003968 // We don't test for ARM yet, and the assertion makes sure that we
3969 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003970 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3971 locations->AddTemp(Location::RequiresRegister());
3972 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00003973 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
3974 // We need a temporary register for the read barrier marking slow
3975 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
3976 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003977 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003978}
3979
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003980Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3981 Opcode opcode) {
3982 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3983 if (constant->IsConstant() &&
3984 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3985 return Location::ConstantLocation(constant->AsConstant());
3986 }
3987 return Location::RequiresRegister();
3988}
3989
3990bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3991 Opcode opcode) {
3992 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3993 if (Primitive::Is64BitType(input_cst->GetType())) {
3994 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3995 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3996 } else {
3997 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3998 }
3999}
4000
4001bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4002 ShifterOperand so;
4003 ArmAssembler* assembler = codegen_->GetAssembler();
4004 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4005 return true;
4006 }
4007 Opcode neg_opcode = kNoOperand;
4008 switch (opcode) {
4009 case AND:
4010 neg_opcode = BIC;
4011 break;
4012 case ORR:
4013 neg_opcode = ORN;
4014 break;
4015 default:
4016 return false;
4017 }
4018 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4019}
4020
Calin Juravle52c48962014-12-16 17:02:57 +00004021void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4022 const FieldInfo& field_info) {
4023 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004024
Calin Juravle52c48962014-12-16 17:02:57 +00004025 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004026 Location base_loc = locations->InAt(0);
4027 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004028 Location out = locations->Out();
4029 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004030 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004031 Primitive::Type field_type = field_info.GetFieldType();
4032 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4033
4034 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004035 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004036 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004037 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004038
Roland Levillainc9285912015-12-18 10:38:42 +00004039 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004040 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004041 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004042
Roland Levillainc9285912015-12-18 10:38:42 +00004043 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004044 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004045 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004046
Roland Levillainc9285912015-12-18 10:38:42 +00004047 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004048 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004049 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004050
4051 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004052 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004053 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004054
4055 case Primitive::kPrimNot: {
4056 // /* HeapReference<Object> */ out = *(base + offset)
4057 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4058 Location temp_loc = locations->GetTemp(0);
4059 // Note that a potential implicit null check is handled in this
4060 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4061 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4062 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4063 if (is_volatile) {
4064 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4065 }
4066 } else {
4067 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4068 codegen_->MaybeRecordImplicitNullCheck(instruction);
4069 if (is_volatile) {
4070 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4071 }
4072 // If read barriers are enabled, emit read barriers other than
4073 // Baker's using a slow path (and also unpoison the loaded
4074 // reference, if heap poisoning is enabled).
4075 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4076 }
4077 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004078 }
4079
Roland Levillainc9285912015-12-18 10:38:42 +00004080 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004081 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004082 GenerateWideAtomicLoad(base, offset,
4083 out.AsRegisterPairLow<Register>(),
4084 out.AsRegisterPairHigh<Register>());
4085 } else {
4086 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4087 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004088 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004089
Roland Levillainc9285912015-12-18 10:38:42 +00004090 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004091 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004092 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004093
4094 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004095 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004096 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004097 Register lo = locations->GetTemp(0).AsRegister<Register>();
4098 Register hi = locations->GetTemp(1).AsRegister<Register>();
4099 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004100 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004101 __ vmovdrr(out_reg, lo, hi);
4102 } else {
4103 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004104 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004105 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004106 break;
4107 }
4108
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004109 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004110 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004111 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004112 }
Calin Juravle52c48962014-12-16 17:02:57 +00004113
Roland Levillainc9285912015-12-18 10:38:42 +00004114 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4115 // Potential implicit null checks, in the case of reference or
4116 // double fields, are handled in the previous switch statement.
4117 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004118 codegen_->MaybeRecordImplicitNullCheck(instruction);
4119 }
4120
Calin Juravle52c48962014-12-16 17:02:57 +00004121 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004122 if (field_type == Primitive::kPrimNot) {
4123 // Memory barriers, in the case of references, are also handled
4124 // in the previous switch statement.
4125 } else {
4126 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4127 }
Roland Levillain4d027112015-07-01 15:41:14 +01004128 }
Calin Juravle52c48962014-12-16 17:02:57 +00004129}
4130
4131void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4132 HandleFieldSet(instruction, instruction->GetFieldInfo());
4133}
4134
4135void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004136 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004137}
4138
4139void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4140 HandleFieldGet(instruction, instruction->GetFieldInfo());
4141}
4142
4143void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4144 HandleFieldGet(instruction, instruction->GetFieldInfo());
4145}
4146
4147void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4148 HandleFieldGet(instruction, instruction->GetFieldInfo());
4149}
4150
4151void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4152 HandleFieldGet(instruction, instruction->GetFieldInfo());
4153}
4154
4155void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4156 HandleFieldSet(instruction, instruction->GetFieldInfo());
4157}
4158
4159void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004160 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004161}
4162
Calin Juravlee460d1d2015-09-29 04:52:17 +01004163void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4164 HUnresolvedInstanceFieldGet* instruction) {
4165 FieldAccessCallingConventionARM calling_convention;
4166 codegen_->CreateUnresolvedFieldLocationSummary(
4167 instruction, instruction->GetFieldType(), calling_convention);
4168}
4169
4170void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4171 HUnresolvedInstanceFieldGet* instruction) {
4172 FieldAccessCallingConventionARM calling_convention;
4173 codegen_->GenerateUnresolvedFieldAccess(instruction,
4174 instruction->GetFieldType(),
4175 instruction->GetFieldIndex(),
4176 instruction->GetDexPc(),
4177 calling_convention);
4178}
4179
4180void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4181 HUnresolvedInstanceFieldSet* instruction) {
4182 FieldAccessCallingConventionARM calling_convention;
4183 codegen_->CreateUnresolvedFieldLocationSummary(
4184 instruction, instruction->GetFieldType(), calling_convention);
4185}
4186
4187void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4188 HUnresolvedInstanceFieldSet* instruction) {
4189 FieldAccessCallingConventionARM calling_convention;
4190 codegen_->GenerateUnresolvedFieldAccess(instruction,
4191 instruction->GetFieldType(),
4192 instruction->GetFieldIndex(),
4193 instruction->GetDexPc(),
4194 calling_convention);
4195}
4196
4197void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4198 HUnresolvedStaticFieldGet* instruction) {
4199 FieldAccessCallingConventionARM calling_convention;
4200 codegen_->CreateUnresolvedFieldLocationSummary(
4201 instruction, instruction->GetFieldType(), calling_convention);
4202}
4203
4204void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4205 HUnresolvedStaticFieldGet* instruction) {
4206 FieldAccessCallingConventionARM calling_convention;
4207 codegen_->GenerateUnresolvedFieldAccess(instruction,
4208 instruction->GetFieldType(),
4209 instruction->GetFieldIndex(),
4210 instruction->GetDexPc(),
4211 calling_convention);
4212}
4213
4214void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4215 HUnresolvedStaticFieldSet* instruction) {
4216 FieldAccessCallingConventionARM calling_convention;
4217 codegen_->CreateUnresolvedFieldLocationSummary(
4218 instruction, instruction->GetFieldType(), calling_convention);
4219}
4220
4221void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4222 HUnresolvedStaticFieldSet* instruction) {
4223 FieldAccessCallingConventionARM calling_convention;
4224 codegen_->GenerateUnresolvedFieldAccess(instruction,
4225 instruction->GetFieldType(),
4226 instruction->GetFieldIndex(),
4227 instruction->GetDexPc(),
4228 calling_convention);
4229}
4230
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004231void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004232 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4233 ? LocationSummary::kCallOnSlowPath
4234 : LocationSummary::kNoCall;
4235 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004236 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004237 if (instruction->HasUses()) {
4238 locations->SetOut(Location::SameAsFirstInput());
4239 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004240}
4241
Calin Juravle2ae48182016-03-16 14:05:09 +00004242void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4243 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004244 return;
4245 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004246 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004247
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004248 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004249 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004250}
4251
Calin Juravle2ae48182016-03-16 14:05:09 +00004252void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004253 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004254 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004255
4256 LocationSummary* locations = instruction->GetLocations();
4257 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004258
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004259 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004260}
4261
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004262void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004263 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004264}
4265
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004266void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004267 bool object_array_get_with_read_barrier =
4268 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004269 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004270 new (GetGraph()->GetArena()) LocationSummary(instruction,
4271 object_array_get_with_read_barrier ?
4272 LocationSummary::kCallOnSlowPath :
4273 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004274 locations->SetInAt(0, Location::RequiresRegister());
4275 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004276 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4277 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4278 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004279 // The output overlaps in the case of an object array get with
4280 // read barriers enabled: we do not want the move to overwrite the
4281 // array's location, as we need it to emit the read barrier.
4282 locations->SetOut(
4283 Location::RequiresRegister(),
4284 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004285 }
Roland Levillainc9285912015-12-18 10:38:42 +00004286 // We need a temporary register for the read barrier marking slow
4287 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4288 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4289 locations->AddTemp(Location::RequiresRegister());
4290 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004291}
4292
4293void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4294 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004295 Location obj_loc = locations->InAt(0);
4296 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004297 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004298 Location out_loc = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004299
Roland Levillainc9285912015-12-18 10:38:42 +00004300 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004301 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004302 case Primitive::kPrimBoolean: {
4303 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004304 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004305 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004306 size_t offset =
4307 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004308 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4309 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004310 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004311 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4312 }
4313 break;
4314 }
4315
4316 case Primitive::kPrimByte: {
4317 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004318 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004319 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004320 size_t offset =
4321 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004322 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4323 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004324 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004325 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4326 }
4327 break;
4328 }
4329
4330 case Primitive::kPrimShort: {
4331 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004332 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004333 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004334 size_t offset =
4335 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004336 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4337 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004338 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004339 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4340 }
4341 break;
4342 }
4343
4344 case Primitive::kPrimChar: {
4345 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004346 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004347 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004348 size_t offset =
4349 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004350 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4351 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004352 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004353 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4354 }
4355 break;
4356 }
4357
Roland Levillainc9285912015-12-18 10:38:42 +00004358 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004359 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004360 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004361 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004362 size_t offset =
4363 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004364 __ LoadFromOffset(kLoadWord, out, obj, offset);
4365 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004366 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004367 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4368 }
4369 break;
4370 }
4371
Roland Levillainc9285912015-12-18 10:38:42 +00004372 case Primitive::kPrimNot: {
4373 static_assert(
4374 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4375 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4376 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4377 // /* HeapReference<Object> */ out =
4378 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4379 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4380 Location temp = locations->GetTemp(0);
4381 // Note that a potential implicit null check is handled in this
4382 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4383 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4384 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4385 } else {
4386 Register out = out_loc.AsRegister<Register>();
4387 if (index.IsConstant()) {
4388 size_t offset =
4389 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4390 __ LoadFromOffset(kLoadWord, out, obj, offset);
4391 codegen_->MaybeRecordImplicitNullCheck(instruction);
4392 // If read barriers are enabled, emit read barriers other than
4393 // Baker's using a slow path (and also unpoison the loaded
4394 // reference, if heap poisoning is enabled).
4395 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4396 } else {
4397 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4398 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4399 codegen_->MaybeRecordImplicitNullCheck(instruction);
4400 // If read barriers are enabled, emit read barriers other than
4401 // Baker's using a slow path (and also unpoison the loaded
4402 // reference, if heap poisoning is enabled).
4403 codegen_->MaybeGenerateReadBarrierSlow(
4404 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4405 }
4406 }
4407 break;
4408 }
4409
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004410 case Primitive::kPrimLong: {
4411 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004412 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004413 size_t offset =
4414 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004415 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004416 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004417 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004418 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004419 }
4420 break;
4421 }
4422
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004423 case Primitive::kPrimFloat: {
4424 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004425 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004426 if (index.IsConstant()) {
4427 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004428 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004429 } else {
4430 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00004431 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004432 }
4433 break;
4434 }
4435
4436 case Primitive::kPrimDouble: {
4437 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004438 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004439 if (index.IsConstant()) {
4440 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004441 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004442 } else {
4443 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004444 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004445 }
4446 break;
4447 }
4448
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004449 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004450 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004451 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004452 }
Roland Levillain4d027112015-07-01 15:41:14 +01004453
4454 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00004455 // Potential implicit null checks, in the case of reference
4456 // arrays, are handled in the previous switch statement.
4457 } else {
4458 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004459 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004460}
4461
4462void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004463 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004464
4465 bool needs_write_barrier =
4466 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004467 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4468 bool object_array_set_with_read_barrier =
4469 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004470
Nicolas Geoffray39468442014-09-02 15:17:15 +01004471 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004472 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004473 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4474 LocationSummary::kCallOnSlowPath :
4475 LocationSummary::kNoCall);
4476
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004477 locations->SetInAt(0, Location::RequiresRegister());
4478 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4479 if (Primitive::IsFloatingPointType(value_type)) {
4480 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004481 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004482 locations->SetInAt(2, Location::RequiresRegister());
4483 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004484 if (needs_write_barrier) {
4485 // Temporary registers for the write barrier.
4486 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004487 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004488 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004489}
4490
4491void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4492 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004493 Location array_loc = locations->InAt(0);
4494 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004495 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004496 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004497 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004498 bool needs_write_barrier =
4499 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004500
4501 switch (value_type) {
4502 case Primitive::kPrimBoolean:
4503 case Primitive::kPrimByte: {
4504 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004505 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004506 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004507 size_t offset =
4508 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004509 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004510 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004511 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004512 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4513 }
4514 break;
4515 }
4516
4517 case Primitive::kPrimShort:
4518 case Primitive::kPrimChar: {
4519 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004520 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004521 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004522 size_t offset =
4523 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004524 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004525 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004526 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004527 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4528 }
4529 break;
4530 }
4531
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004532 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004533 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004534 Location value_loc = locations->InAt(2);
4535 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004536 Register source = value;
4537
4538 if (instruction->InputAt(2)->IsNullConstant()) {
4539 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004540 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004541 size_t offset =
4542 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004543 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004544 } else {
4545 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004546 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004547 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004548 }
Roland Levillain1407ee72016-01-08 15:56:19 +00004549 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00004550 DCHECK(!needs_write_barrier);
4551 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004552 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004553 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004554
4555 DCHECK(needs_write_barrier);
4556 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4557 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4558 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4559 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4560 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4561 Label done;
4562 SlowPathCode* slow_path = nullptr;
4563
Roland Levillain3b359c72015-11-17 19:35:12 +00004564 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004565 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4566 codegen_->AddSlowPath(slow_path);
4567 if (instruction->GetValueCanBeNull()) {
4568 Label non_zero;
4569 __ CompareAndBranchIfNonZero(value, &non_zero);
4570 if (index.IsConstant()) {
4571 size_t offset =
4572 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4573 __ StoreToOffset(kStoreWord, value, array, offset);
4574 } else {
4575 DCHECK(index.IsRegister()) << index;
4576 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4577 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4578 }
4579 codegen_->MaybeRecordImplicitNullCheck(instruction);
4580 __ b(&done);
4581 __ Bind(&non_zero);
4582 }
4583
Roland Levillain3b359c72015-11-17 19:35:12 +00004584 if (kEmitCompilerReadBarrier) {
4585 // When read barriers are enabled, the type checking
4586 // instrumentation requires two read barriers:
4587 //
4588 // __ Mov(temp2, temp1);
4589 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4590 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004591 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004592 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4593 //
4594 // // /* HeapReference<Class> */ temp2 = value->klass_
4595 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004596 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004597 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4598 //
4599 // __ cmp(temp1, ShifterOperand(temp2));
4600 //
4601 // However, the second read barrier may trash `temp`, as it
4602 // is a temporary register, and as such would not be saved
4603 // along with live registers before calling the runtime (nor
4604 // restored afterwards). So in this case, we bail out and
4605 // delegate the work to the array set slow path.
4606 //
4607 // TODO: Extend the register allocator to support a new
4608 // "(locally) live temp" location so as to avoid always
4609 // going into the slow path when read barriers are enabled.
4610 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004611 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004612 // /* HeapReference<Class> */ temp1 = array->klass_
4613 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4614 codegen_->MaybeRecordImplicitNullCheck(instruction);
4615 __ MaybeUnpoisonHeapReference(temp1);
4616
4617 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4618 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4619 // /* HeapReference<Class> */ temp2 = value->klass_
4620 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4621 // If heap poisoning is enabled, no need to unpoison `temp1`
4622 // nor `temp2`, as we are comparing two poisoned references.
4623 __ cmp(temp1, ShifterOperand(temp2));
4624
4625 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4626 Label do_put;
4627 __ b(&do_put, EQ);
4628 // If heap poisoning is enabled, the `temp1` reference has
4629 // not been unpoisoned yet; unpoison it now.
4630 __ MaybeUnpoisonHeapReference(temp1);
4631
4632 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4633 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4634 // If heap poisoning is enabled, no need to unpoison
4635 // `temp1`, as we are comparing against null below.
4636 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4637 __ Bind(&do_put);
4638 } else {
4639 __ b(slow_path->GetEntryLabel(), NE);
4640 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004641 }
4642 }
4643
4644 if (kPoisonHeapReferences) {
4645 // Note that in the case where `value` is a null reference,
4646 // we do not enter this block, as a null reference does not
4647 // need poisoning.
4648 DCHECK_EQ(value_type, Primitive::kPrimNot);
4649 __ Mov(temp1, value);
4650 __ PoisonHeapReference(temp1);
4651 source = temp1;
4652 }
4653
4654 if (index.IsConstant()) {
4655 size_t offset =
4656 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4657 __ StoreToOffset(kStoreWord, source, array, offset);
4658 } else {
4659 DCHECK(index.IsRegister()) << index;
4660 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4661 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4662 }
4663
Roland Levillain3b359c72015-11-17 19:35:12 +00004664 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004665 codegen_->MaybeRecordImplicitNullCheck(instruction);
4666 }
4667
4668 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4669
4670 if (done.IsLinked()) {
4671 __ Bind(&done);
4672 }
4673
4674 if (slow_path != nullptr) {
4675 __ Bind(slow_path->GetExitLabel());
4676 }
4677
4678 break;
4679 }
4680
4681 case Primitive::kPrimInt: {
4682 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4683 Register value = locations->InAt(2).AsRegister<Register>();
4684 if (index.IsConstant()) {
4685 size_t offset =
4686 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4687 __ StoreToOffset(kStoreWord, value, array, offset);
4688 } else {
4689 DCHECK(index.IsRegister()) << index;
4690 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4691 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4692 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004693 break;
4694 }
4695
4696 case Primitive::kPrimLong: {
4697 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004698 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004699 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004700 size_t offset =
4701 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004702 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004703 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004704 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004705 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004706 }
4707 break;
4708 }
4709
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004710 case Primitive::kPrimFloat: {
4711 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4712 Location value = locations->InAt(2);
4713 DCHECK(value.IsFpuRegister());
4714 if (index.IsConstant()) {
4715 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004716 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004717 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004718 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004719 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4720 }
4721 break;
4722 }
4723
4724 case Primitive::kPrimDouble: {
4725 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4726 Location value = locations->InAt(2);
4727 DCHECK(value.IsFpuRegisterPair());
4728 if (index.IsConstant()) {
4729 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004730 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004731 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004732 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004733 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4734 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004735
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004736 break;
4737 }
4738
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004739 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004740 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004741 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004742 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004743
Roland Levillain80e67092016-01-08 16:04:55 +00004744 // Objects are handled in the switch.
4745 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004746 codegen_->MaybeRecordImplicitNullCheck(instruction);
4747 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004748}
4749
4750void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004751 LocationSummary* locations =
4752 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004753 locations->SetInAt(0, Location::RequiresRegister());
4754 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004755}
4756
4757void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4758 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01004759 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004760 Register obj = locations->InAt(0).AsRegister<Register>();
4761 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004762 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004763 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004764}
4765
4766void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004767 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4768 ? LocationSummary::kCallOnSlowPath
4769 : LocationSummary::kNoCall;
4770 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004771 locations->SetInAt(0, Location::RequiresRegister());
4772 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004773 if (instruction->HasUses()) {
4774 locations->SetOut(Location::SameAsFirstInput());
4775 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004776}
4777
4778void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4779 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004780 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004781 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004782 codegen_->AddSlowPath(slow_path);
4783
Roland Levillain271ab9c2014-11-27 15:23:57 +00004784 Register index = locations->InAt(0).AsRegister<Register>();
4785 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004786
4787 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004788 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004789}
4790
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004791void CodeGeneratorARM::MarkGCCard(Register temp,
4792 Register card,
4793 Register object,
4794 Register value,
4795 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004796 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004797 if (can_be_null) {
4798 __ CompareAndBranchIfZero(value, &is_null);
4799 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004800 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4801 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4802 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004803 if (can_be_null) {
4804 __ Bind(&is_null);
4805 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004806}
4807
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004808void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004809 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004810}
4811
4812void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004813 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4814}
4815
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004816void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4817 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4818}
4819
4820void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004821 HBasicBlock* block = instruction->GetBlock();
4822 if (block->GetLoopInformation() != nullptr) {
4823 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4824 // The back edge will generate the suspend check.
4825 return;
4826 }
4827 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4828 // The goto will generate the suspend check.
4829 return;
4830 }
4831 GenerateSuspendCheck(instruction, nullptr);
4832}
4833
4834void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4835 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004836 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004837 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4838 if (slow_path == nullptr) {
4839 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4840 instruction->SetSlowPath(slow_path);
4841 codegen_->AddSlowPath(slow_path);
4842 if (successor != nullptr) {
4843 DCHECK(successor->IsLoopHeader());
4844 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4845 }
4846 } else {
4847 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4848 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004849
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004850 __ LoadFromOffset(
4851 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004852 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004853 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004854 __ Bind(slow_path->GetReturnLabel());
4855 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004856 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004857 __ b(slow_path->GetEntryLabel());
4858 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004859}
4860
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004861ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4862 return codegen_->GetAssembler();
4863}
4864
4865void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004866 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004867 Location source = move->GetSource();
4868 Location destination = move->GetDestination();
4869
4870 if (source.IsRegister()) {
4871 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004872 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004873 } else if (destination.IsFpuRegister()) {
4874 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004875 } else {
4876 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004877 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004878 SP, destination.GetStackIndex());
4879 }
4880 } else if (source.IsStackSlot()) {
4881 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004882 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004883 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004884 } else if (destination.IsFpuRegister()) {
4885 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004886 } else {
4887 DCHECK(destination.IsStackSlot());
4888 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4889 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4890 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004891 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004892 if (destination.IsRegister()) {
4893 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
4894 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004895 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004896 } else {
4897 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004898 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4899 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004900 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004901 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004902 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4903 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004904 } else if (destination.IsRegisterPair()) {
4905 DCHECK(ExpectedPairLayout(destination));
4906 __ LoadFromOffset(
4907 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4908 } else {
4909 DCHECK(destination.IsFpuRegisterPair()) << destination;
4910 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4911 SP,
4912 source.GetStackIndex());
4913 }
4914 } else if (source.IsRegisterPair()) {
4915 if (destination.IsRegisterPair()) {
4916 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4917 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004918 } else if (destination.IsFpuRegisterPair()) {
4919 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4920 source.AsRegisterPairLow<Register>(),
4921 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004922 } else {
4923 DCHECK(destination.IsDoubleStackSlot()) << destination;
4924 DCHECK(ExpectedPairLayout(source));
4925 __ StoreToOffset(
4926 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4927 }
4928 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004929 if (destination.IsRegisterPair()) {
4930 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4931 destination.AsRegisterPairHigh<Register>(),
4932 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4933 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004934 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4935 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4936 } else {
4937 DCHECK(destination.IsDoubleStackSlot()) << destination;
4938 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4939 SP,
4940 destination.GetStackIndex());
4941 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004942 } else {
4943 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004944 HConstant* constant = source.GetConstant();
4945 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4946 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004947 if (destination.IsRegister()) {
4948 __ LoadImmediate(destination.AsRegister<Register>(), value);
4949 } else {
4950 DCHECK(destination.IsStackSlot());
4951 __ LoadImmediate(IP, value);
4952 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4953 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004954 } else if (constant->IsLongConstant()) {
4955 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004956 if (destination.IsRegisterPair()) {
4957 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4958 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004959 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004960 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004961 __ LoadImmediate(IP, Low32Bits(value));
4962 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4963 __ LoadImmediate(IP, High32Bits(value));
4964 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4965 }
4966 } else if (constant->IsDoubleConstant()) {
4967 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004968 if (destination.IsFpuRegisterPair()) {
4969 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004970 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004971 DCHECK(destination.IsDoubleStackSlot()) << destination;
4972 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004973 __ LoadImmediate(IP, Low32Bits(int_value));
4974 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4975 __ LoadImmediate(IP, High32Bits(int_value));
4976 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4977 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004978 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004979 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004980 float value = constant->AsFloatConstant()->GetValue();
4981 if (destination.IsFpuRegister()) {
4982 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4983 } else {
4984 DCHECK(destination.IsStackSlot());
4985 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4986 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4987 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004988 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004989 }
4990}
4991
4992void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4993 __ Mov(IP, reg);
4994 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4995 __ StoreToOffset(kStoreWord, IP, SP, mem);
4996}
4997
4998void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4999 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5000 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5001 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5002 SP, mem1 + stack_offset);
5003 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5004 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5005 SP, mem2 + stack_offset);
5006 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5007}
5008
5009void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005010 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005011 Location source = move->GetSource();
5012 Location destination = move->GetDestination();
5013
5014 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005015 DCHECK_NE(source.AsRegister<Register>(), IP);
5016 DCHECK_NE(destination.AsRegister<Register>(), IP);
5017 __ Mov(IP, source.AsRegister<Register>());
5018 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5019 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005020 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005021 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005022 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005023 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005024 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5025 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005026 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005027 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005028 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005029 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005030 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005031 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005032 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005033 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005034 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5035 destination.AsRegisterPairHigh<Register>(),
5036 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005037 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005038 Register low_reg = source.IsRegisterPair()
5039 ? source.AsRegisterPairLow<Register>()
5040 : destination.AsRegisterPairLow<Register>();
5041 int mem = source.IsRegisterPair()
5042 ? destination.GetStackIndex()
5043 : source.GetStackIndex();
5044 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005045 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005046 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005047 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005048 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005049 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5050 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005051 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005052 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005053 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005054 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5055 DRegister reg = source.IsFpuRegisterPair()
5056 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5057 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5058 int mem = source.IsFpuRegisterPair()
5059 ? destination.GetStackIndex()
5060 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005061 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005062 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005063 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005064 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5065 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5066 : destination.AsFpuRegister<SRegister>();
5067 int mem = source.IsFpuRegister()
5068 ? destination.GetStackIndex()
5069 : source.GetStackIndex();
5070
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005071 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005072 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005073 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005074 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005075 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5076 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005077 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005078 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005079 }
5080}
5081
5082void ParallelMoveResolverARM::SpillScratch(int reg) {
5083 __ Push(static_cast<Register>(reg));
5084}
5085
5086void ParallelMoveResolverARM::RestoreScratch(int reg) {
5087 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005088}
5089
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005090void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005091 InvokeRuntimeCallingConvention calling_convention;
5092 CodeGenerator::CreateLoadClassLocationSummary(
5093 cls,
5094 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain3b359c72015-11-17 19:35:12 +00005095 Location::RegisterLocation(R0),
5096 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005097}
5098
5099void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005100 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005101 if (cls->NeedsAccessCheck()) {
5102 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5103 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5104 cls,
5105 cls->GetDexPc(),
5106 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005107 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005108 return;
5109 }
5110
Roland Levillain3b359c72015-11-17 19:35:12 +00005111 Location out_loc = locations->Out();
5112 Register out = out_loc.AsRegister<Register>();
Calin Juravle580b6092015-10-06 17:35:58 +01005113 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005114
Calin Juravle580b6092015-10-06 17:35:58 +01005115 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005116 DCHECK(!cls->CanCallRuntime());
5117 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillainc9285912015-12-18 10:38:42 +00005118 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5119 GenerateGcRootFieldLoad(
5120 cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005121 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00005122 // /* GcRoot<mirror::Class>[] */ out =
5123 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005124 __ LoadFromOffset(kLoadWord,
5125 out,
5126 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01005127 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Roland Levillainc9285912015-12-18 10:38:42 +00005128 // /* GcRoot<mirror::Class> */ out = out[type_index]
5129 GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005130
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005131 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5132 DCHECK(cls->CanCallRuntime());
5133 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5134 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5135 codegen_->AddSlowPath(slow_path);
5136 if (!cls->IsInDexCache()) {
5137 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5138 }
5139 if (cls->MustGenerateClinitCheck()) {
5140 GenerateClassInitializationCheck(slow_path, out);
5141 } else {
5142 __ Bind(slow_path->GetExitLabel());
5143 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005144 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005145 }
5146}
5147
5148void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5149 LocationSummary* locations =
5150 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5151 locations->SetInAt(0, Location::RequiresRegister());
5152 if (check->HasUses()) {
5153 locations->SetOut(Location::SameAsFirstInput());
5154 }
5155}
5156
5157void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005158 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005159 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005160 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005161 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005162 GenerateClassInitializationCheck(slow_path,
5163 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005164}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005165
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005166void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005167 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005168 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5169 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5170 __ b(slow_path->GetEntryLabel(), LT);
5171 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5172 // properly. Therefore, we do a memory fence.
5173 __ dmb(ISH);
5174 __ Bind(slow_path->GetExitLabel());
5175}
5176
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005177HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5178 HLoadString::LoadKind desired_string_load_kind) {
5179 if (kEmitCompilerReadBarrier) {
5180 switch (desired_string_load_kind) {
5181 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5182 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5183 case HLoadString::LoadKind::kBootImageAddress:
5184 // TODO: Implement for read barrier.
5185 return HLoadString::LoadKind::kDexCacheViaMethod;
5186 default:
5187 break;
5188 }
5189 }
5190 switch (desired_string_load_kind) {
5191 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5192 DCHECK(!GetCompilerOptions().GetCompilePic());
5193 break;
5194 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5195 DCHECK(GetCompilerOptions().GetCompilePic());
5196 break;
5197 case HLoadString::LoadKind::kBootImageAddress:
5198 break;
5199 case HLoadString::LoadKind::kDexCacheAddress:
Calin Juravleffc87072016-04-20 14:22:09 +01005200 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005201 break;
5202 case HLoadString::LoadKind::kDexCachePcRelative:
Calin Juravleffc87072016-04-20 14:22:09 +01005203 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005204 // We disable pc-relative load when there is an irreducible loop, as the optimization
5205 // is incompatible with it.
5206 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5207 // with irreducible loops.
5208 if (GetGraph()->HasIrreducibleLoops()) {
5209 return HLoadString::LoadKind::kDexCacheViaMethod;
5210 }
5211 break;
5212 case HLoadString::LoadKind::kDexCacheViaMethod:
5213 break;
5214 }
5215 return desired_string_load_kind;
5216}
5217
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005218void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005219 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005220 ? LocationSummary::kCallOnSlowPath
5221 : LocationSummary::kNoCall;
5222 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005223 HLoadString::LoadKind load_kind = load->GetLoadKind();
5224 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5225 load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5226 locations->SetInAt(0, Location::RequiresRegister());
5227 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005228 locations->SetOut(Location::RequiresRegister());
5229}
5230
5231void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005232 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005233 Location out_loc = locations->Out();
5234 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005235
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005236 switch (load->GetLoadKind()) {
5237 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5238 DCHECK(!kEmitCompilerReadBarrier);
5239 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5240 load->GetStringIndex()));
5241 return; // No dex cache slow path.
5242 }
5243 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5244 DCHECK(!kEmitCompilerReadBarrier);
5245 CodeGeneratorARM::PcRelativePatchInfo* labels =
5246 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5247 __ BindTrackedLabel(&labels->movw_label);
5248 __ movw(out, /* placeholder */ 0u);
5249 __ BindTrackedLabel(&labels->movt_label);
5250 __ movt(out, /* placeholder */ 0u);
5251 __ BindTrackedLabel(&labels->add_pc_label);
5252 __ add(out, out, ShifterOperand(PC));
5253 return; // No dex cache slow path.
5254 }
5255 case HLoadString::LoadKind::kBootImageAddress: {
5256 DCHECK(!kEmitCompilerReadBarrier);
5257 DCHECK_NE(load->GetAddress(), 0u);
5258 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5259 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5260 return; // No dex cache slow path.
5261 }
5262 case HLoadString::LoadKind::kDexCacheAddress: {
5263 DCHECK_NE(load->GetAddress(), 0u);
5264 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5265 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5266 // a 128B range. To try and reduce the number of literals if we load multiple strings,
5267 // simply split the dex cache address to a 128B aligned base loaded from a literal
5268 // and the remaining offset embedded in the load.
5269 static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5270 DCHECK_ALIGNED(load->GetAddress(), 4u);
5271 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5272 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5273 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5274 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5275 GenerateGcRootFieldLoad(load, out_loc, out, offset);
5276 break;
5277 }
5278 case HLoadString::LoadKind::kDexCachePcRelative: {
5279 Register base_reg = locations->InAt(0).AsRegister<Register>();
5280 HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5281 int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
5282 GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5283 break;
5284 }
5285 case HLoadString::LoadKind::kDexCacheViaMethod: {
5286 Register current_method = locations->InAt(0).AsRegister<Register>();
5287
5288 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5289 GenerateGcRootFieldLoad(
5290 load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5291 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5292 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5293 // /* GcRoot<mirror::String> */ out = out[string_index]
5294 GenerateGcRootFieldLoad(
5295 load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5296 break;
5297 }
5298 default:
5299 LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5300 UNREACHABLE();
5301 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005302
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005303 if (!load->IsInDexCache()) {
5304 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5305 codegen_->AddSlowPath(slow_path);
5306 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5307 __ Bind(slow_path->GetExitLabel());
5308 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005309}
5310
David Brazdilcb1c0552015-08-04 16:22:25 +01005311static int32_t GetExceptionTlsOffset() {
5312 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5313}
5314
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005315void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5316 LocationSummary* locations =
5317 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5318 locations->SetOut(Location::RequiresRegister());
5319}
5320
5321void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005322 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005323 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5324}
5325
5326void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5327 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5328}
5329
5330void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005331 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005332 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005333}
5334
5335void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5336 LocationSummary* locations =
5337 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5338 InvokeRuntimeCallingConvention calling_convention;
5339 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5340}
5341
5342void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5343 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005344 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005345 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005346}
5347
Roland Levillainc9285912015-12-18 10:38:42 +00005348static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5349 return kEmitCompilerReadBarrier &&
5350 (kUseBakerReadBarrier ||
5351 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5352 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5353 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5354}
5355
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005356void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005357 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005358 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5359 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005360 case TypeCheckKind::kExactCheck:
5361 case TypeCheckKind::kAbstractClassCheck:
5362 case TypeCheckKind::kClassHierarchyCheck:
5363 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005364 call_kind =
5365 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005366 break;
5367 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005368 case TypeCheckKind::kUnresolvedCheck:
5369 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005370 call_kind = LocationSummary::kCallOnSlowPath;
5371 break;
5372 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005373
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005374 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005375 locations->SetInAt(0, Location::RequiresRegister());
5376 locations->SetInAt(1, Location::RequiresRegister());
5377 // The "out" register is used as a temporary, so it overlaps with the inputs.
5378 // Note that TypeCheckSlowPathARM uses this register too.
5379 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5380 // When read barriers are enabled, we need a temporary register for
5381 // some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005382 if (TypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005383 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005384 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005385}
5386
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005387void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005388 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005389 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005390 Location obj_loc = locations->InAt(0);
5391 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005392 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005393 Location out_loc = locations->Out();
5394 Register out = out_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005395 Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005396 locations->GetTemp(0) :
5397 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005398 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005399 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5400 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5401 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005402 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005403 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005404
5405 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005406 // avoid null check if we know obj is not null.
5407 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005408 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005409 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005410
Roland Levillain3b359c72015-11-17 19:35:12 +00005411 // /* HeapReference<Class> */ out = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005412 GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005413
Roland Levillainc9285912015-12-18 10:38:42 +00005414 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005415 case TypeCheckKind::kExactCheck: {
5416 __ cmp(out, ShifterOperand(cls));
5417 // Classes must be equal for the instanceof to succeed.
5418 __ b(&zero, NE);
5419 __ LoadImmediate(out, 1);
5420 __ b(&done);
5421 break;
5422 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005423
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005424 case TypeCheckKind::kAbstractClassCheck: {
5425 // If the class is abstract, we eagerly fetch the super class of the
5426 // object to avoid doing a comparison we know will fail.
5427 Label loop;
5428 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005429 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005430 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005431 // If `out` is null, we use it for the result, and jump to `done`.
5432 __ CompareAndBranchIfZero(out, &done);
5433 __ cmp(out, ShifterOperand(cls));
5434 __ b(&loop, NE);
5435 __ LoadImmediate(out, 1);
5436 if (zero.IsLinked()) {
5437 __ b(&done);
5438 }
5439 break;
5440 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005441
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005442 case TypeCheckKind::kClassHierarchyCheck: {
5443 // Walk over the class hierarchy to find a match.
5444 Label loop, success;
5445 __ Bind(&loop);
5446 __ cmp(out, ShifterOperand(cls));
5447 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005448 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005449 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005450 __ CompareAndBranchIfNonZero(out, &loop);
5451 // If `out` is null, we use it for the result, and jump to `done`.
5452 __ b(&done);
5453 __ Bind(&success);
5454 __ LoadImmediate(out, 1);
5455 if (zero.IsLinked()) {
5456 __ b(&done);
5457 }
5458 break;
5459 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005460
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005461 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005462 // Do an exact check.
5463 Label exact_check;
5464 __ cmp(out, ShifterOperand(cls));
5465 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005466 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005467 // /* HeapReference<Class> */ out = out->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005468 GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005469 // If `out` is null, we use it for the result, and jump to `done`.
5470 __ CompareAndBranchIfZero(out, &done);
5471 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5472 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5473 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005474 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005475 __ LoadImmediate(out, 1);
5476 __ b(&done);
5477 break;
5478 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005479
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005480 case TypeCheckKind::kArrayCheck: {
5481 __ cmp(out, ShifterOperand(cls));
5482 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005483 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5484 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005485 codegen_->AddSlowPath(slow_path);
5486 __ b(slow_path->GetEntryLabel(), NE);
5487 __ LoadImmediate(out, 1);
5488 if (zero.IsLinked()) {
5489 __ b(&done);
5490 }
5491 break;
5492 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005493
Calin Juravle98893e12015-10-02 21:05:03 +01005494 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005495 case TypeCheckKind::kInterfaceCheck: {
5496 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005497 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00005498 // cases.
5499 //
5500 // We cannot directly call the InstanceofNonTrivial runtime
5501 // entry point without resorting to a type checking slow path
5502 // here (i.e. by calling InvokeRuntime directly), as it would
5503 // require to assign fixed registers for the inputs of this
5504 // HInstanceOf instruction (following the runtime calling
5505 // convention), which might be cluttered by the potential first
5506 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005507 //
5508 // TODO: Introduce a new runtime entry point taking the object
5509 // to test (instead of its class) as argument, and let it deal
5510 // with the read barrier issues. This will let us refactor this
5511 // case of the `switch` code as it was previously (with a direct
5512 // call to the runtime not using a type checking slow path).
5513 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005514 DCHECK(locations->OnlyCallsOnSlowPath());
5515 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5516 /* is_fatal */ false);
5517 codegen_->AddSlowPath(slow_path);
5518 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005519 if (zero.IsLinked()) {
5520 __ b(&done);
5521 }
5522 break;
5523 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005524 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005525
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005526 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005527 __ Bind(&zero);
5528 __ LoadImmediate(out, 0);
5529 }
5530
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005531 if (done.IsLinked()) {
5532 __ Bind(&done);
5533 }
5534
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005535 if (slow_path != nullptr) {
5536 __ Bind(slow_path->GetExitLabel());
5537 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005538}
5539
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005540void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005541 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5542 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5543
Roland Levillain3b359c72015-11-17 19:35:12 +00005544 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5545 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005546 case TypeCheckKind::kExactCheck:
5547 case TypeCheckKind::kAbstractClassCheck:
5548 case TypeCheckKind::kClassHierarchyCheck:
5549 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005550 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5551 LocationSummary::kCallOnSlowPath :
5552 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005553 break;
5554 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005555 case TypeCheckKind::kUnresolvedCheck:
5556 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005557 call_kind = LocationSummary::kCallOnSlowPath;
5558 break;
5559 }
5560
Roland Levillain3b359c72015-11-17 19:35:12 +00005561 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5562 locations->SetInAt(0, Location::RequiresRegister());
5563 locations->SetInAt(1, Location::RequiresRegister());
5564 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5565 locations->AddTemp(Location::RequiresRegister());
5566 // When read barriers are enabled, we need an additional temporary
5567 // register for some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005568 if (TypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005569 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005570 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005571}
5572
5573void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005574 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005575 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005576 Location obj_loc = locations->InAt(0);
5577 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005578 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005579 Location temp_loc = locations->GetTemp(0);
5580 Register temp = temp_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005581 Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005582 locations->GetTemp(1) :
5583 Location::NoLocation();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005584 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005585 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5586 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5587 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005588
Roland Levillain3b359c72015-11-17 19:35:12 +00005589 bool is_type_check_slow_path_fatal =
5590 (type_check_kind == TypeCheckKind::kExactCheck ||
5591 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5592 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5593 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5594 !instruction->CanThrowIntoCatchBlock();
5595 SlowPathCode* type_check_slow_path =
5596 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5597 is_type_check_slow_path_fatal);
5598 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005599
5600 Label done;
5601 // Avoid null check if we know obj is not null.
5602 if (instruction->MustDoNullCheck()) {
5603 __ CompareAndBranchIfZero(obj, &done);
5604 }
5605
Roland Levillain3b359c72015-11-17 19:35:12 +00005606 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005607 GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005608
Roland Levillain3b359c72015-11-17 19:35:12 +00005609 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005610 case TypeCheckKind::kExactCheck:
5611 case TypeCheckKind::kArrayCheck: {
5612 __ cmp(temp, ShifterOperand(cls));
5613 // Jump to slow path for throwing the exception or doing a
5614 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005615 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005616 break;
5617 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005618
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005619 case TypeCheckKind::kAbstractClassCheck: {
5620 // If the class is abstract, we eagerly fetch the super class of the
5621 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005622 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005623 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005624 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005625 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005626
5627 // If the class reference currently in `temp` is not null, jump
5628 // to the `compare_classes` label to compare it with the checked
5629 // class.
5630 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5631 // Otherwise, jump to the slow path to throw the exception.
5632 //
5633 // But before, move back the object's class into `temp` before
5634 // going into the slow path, as it has been overwritten in the
5635 // meantime.
5636 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005637 GenerateReferenceLoadTwoRegisters(
5638 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005639 __ b(type_check_slow_path->GetEntryLabel());
5640
5641 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005642 __ cmp(temp, ShifterOperand(cls));
5643 __ b(&loop, NE);
5644 break;
5645 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005646
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005647 case TypeCheckKind::kClassHierarchyCheck: {
5648 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005649 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005650 __ Bind(&loop);
5651 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005652 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005653
Roland Levillain3b359c72015-11-17 19:35:12 +00005654 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005655 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005656
5657 // If the class reference currently in `temp` is not null, jump
5658 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005659 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005660 // Otherwise, jump to the slow path to throw the exception.
5661 //
5662 // But before, move back the object's class into `temp` before
5663 // going into the slow path, as it has been overwritten in the
5664 // meantime.
5665 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005666 GenerateReferenceLoadTwoRegisters(
5667 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005668 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005669 break;
5670 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005671
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005672 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005673 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005674 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005675 __ cmp(temp, ShifterOperand(cls));
5676 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005677
5678 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005679 // /* HeapReference<Class> */ temp = temp->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005680 GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005681
5682 // If the component type is not null (i.e. the object is indeed
5683 // an array), jump to label `check_non_primitive_component_type`
5684 // to further check that this component type is not a primitive
5685 // type.
5686 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5687 // Otherwise, jump to the slow path to throw the exception.
5688 //
5689 // But before, move back the object's class into `temp` before
5690 // going into the slow path, as it has been overwritten in the
5691 // meantime.
5692 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005693 GenerateReferenceLoadTwoRegisters(
5694 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005695 __ b(type_check_slow_path->GetEntryLabel());
5696
5697 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005698 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005699 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5700 __ CompareAndBranchIfZero(temp, &done);
5701 // Same comment as above regarding `temp` and the slow path.
5702 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005703 GenerateReferenceLoadTwoRegisters(
5704 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005705 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005706 break;
5707 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005708
Calin Juravle98893e12015-10-02 21:05:03 +01005709 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005710 case TypeCheckKind::kInterfaceCheck:
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005711 // We always go into the type check slow path for the unresolved
5712 // and interface check cases.
Roland Levillain3b359c72015-11-17 19:35:12 +00005713 //
5714 // We cannot directly call the CheckCast runtime entry point
5715 // without resorting to a type checking slow path here (i.e. by
5716 // calling InvokeRuntime directly), as it would require to
5717 // assign fixed registers for the inputs of this HInstanceOf
5718 // instruction (following the runtime calling convention), which
5719 // might be cluttered by the potential first read barrier
5720 // emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005721 //
5722 // TODO: Introduce a new runtime entry point taking the object
5723 // to test (instead of its class) as argument, and let it deal
5724 // with the read barrier issues. This will let us refactor this
5725 // case of the `switch` code as it was previously (with a direct
5726 // call to the runtime not using a type checking slow path).
5727 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005728 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005729 break;
5730 }
5731 __ Bind(&done);
5732
Roland Levillain3b359c72015-11-17 19:35:12 +00005733 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005734}
5735
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005736void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5737 LocationSummary* locations =
5738 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5739 InvokeRuntimeCallingConvention calling_convention;
5740 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5741}
5742
5743void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5744 codegen_->InvokeRuntime(instruction->IsEnter()
5745 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5746 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005747 instruction->GetDexPc(),
5748 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005749 if (instruction->IsEnter()) {
5750 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5751 } else {
5752 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5753 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005754}
5755
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005756void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5757void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5758void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005759
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005760void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005761 LocationSummary* locations =
5762 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5763 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5764 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005765 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005766 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005767 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005768 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005769}
5770
5771void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5772 HandleBitwiseOperation(instruction);
5773}
5774
5775void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5776 HandleBitwiseOperation(instruction);
5777}
5778
5779void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5780 HandleBitwiseOperation(instruction);
5781}
5782
Artem Serov7fc63502016-02-09 17:15:29 +00005783
5784void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5785 LocationSummary* locations =
5786 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5787 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5788 || instruction->GetResultType() == Primitive::kPrimLong);
5789
5790 locations->SetInAt(0, Location::RequiresRegister());
5791 locations->SetInAt(1, Location::RequiresRegister());
5792 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5793}
5794
5795void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5796 LocationSummary* locations = instruction->GetLocations();
5797 Location first = locations->InAt(0);
5798 Location second = locations->InAt(1);
5799 Location out = locations->Out();
5800
5801 if (instruction->GetResultType() == Primitive::kPrimInt) {
5802 Register first_reg = first.AsRegister<Register>();
5803 ShifterOperand second_reg(second.AsRegister<Register>());
5804 Register out_reg = out.AsRegister<Register>();
5805
5806 switch (instruction->GetOpKind()) {
5807 case HInstruction::kAnd:
5808 __ bic(out_reg, first_reg, second_reg);
5809 break;
5810 case HInstruction::kOr:
5811 __ orn(out_reg, first_reg, second_reg);
5812 break;
5813 // There is no EON on arm.
5814 case HInstruction::kXor:
5815 default:
5816 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5817 UNREACHABLE();
5818 }
5819 return;
5820
5821 } else {
5822 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5823 Register first_low = first.AsRegisterPairLow<Register>();
5824 Register first_high = first.AsRegisterPairHigh<Register>();
5825 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5826 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5827 Register out_low = out.AsRegisterPairLow<Register>();
5828 Register out_high = out.AsRegisterPairHigh<Register>();
5829
5830 switch (instruction->GetOpKind()) {
5831 case HInstruction::kAnd:
5832 __ bic(out_low, first_low, second_low);
5833 __ bic(out_high, first_high, second_high);
5834 break;
5835 case HInstruction::kOr:
5836 __ orn(out_low, first_low, second_low);
5837 __ orn(out_high, first_high, second_high);
5838 break;
5839 // There is no EON on arm.
5840 case HInstruction::kXor:
5841 default:
5842 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5843 UNREACHABLE();
5844 }
5845 }
5846}
5847
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005848void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5849 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5850 if (value == 0xffffffffu) {
5851 if (out != first) {
5852 __ mov(out, ShifterOperand(first));
5853 }
5854 return;
5855 }
5856 if (value == 0u) {
5857 __ mov(out, ShifterOperand(0));
5858 return;
5859 }
5860 ShifterOperand so;
5861 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5862 __ and_(out, first, so);
5863 } else {
5864 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5865 __ bic(out, first, ShifterOperand(~value));
5866 }
5867}
5868
5869void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5870 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5871 if (value == 0u) {
5872 if (out != first) {
5873 __ mov(out, ShifterOperand(first));
5874 }
5875 return;
5876 }
5877 if (value == 0xffffffffu) {
5878 __ mvn(out, ShifterOperand(0));
5879 return;
5880 }
5881 ShifterOperand so;
5882 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5883 __ orr(out, first, so);
5884 } else {
5885 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5886 __ orn(out, first, ShifterOperand(~value));
5887 }
5888}
5889
5890void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5891 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5892 if (value == 0u) {
5893 if (out != first) {
5894 __ mov(out, ShifterOperand(first));
5895 }
5896 return;
5897 }
5898 __ eor(out, first, ShifterOperand(value));
5899}
5900
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005901void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5902 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005903 Location first = locations->InAt(0);
5904 Location second = locations->InAt(1);
5905 Location out = locations->Out();
5906
5907 if (second.IsConstant()) {
5908 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5909 uint32_t value_low = Low32Bits(value);
5910 if (instruction->GetResultType() == Primitive::kPrimInt) {
5911 Register first_reg = first.AsRegister<Register>();
5912 Register out_reg = out.AsRegister<Register>();
5913 if (instruction->IsAnd()) {
5914 GenerateAndConst(out_reg, first_reg, value_low);
5915 } else if (instruction->IsOr()) {
5916 GenerateOrrConst(out_reg, first_reg, value_low);
5917 } else {
5918 DCHECK(instruction->IsXor());
5919 GenerateEorConst(out_reg, first_reg, value_low);
5920 }
5921 } else {
5922 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5923 uint32_t value_high = High32Bits(value);
5924 Register first_low = first.AsRegisterPairLow<Register>();
5925 Register first_high = first.AsRegisterPairHigh<Register>();
5926 Register out_low = out.AsRegisterPairLow<Register>();
5927 Register out_high = out.AsRegisterPairHigh<Register>();
5928 if (instruction->IsAnd()) {
5929 GenerateAndConst(out_low, first_low, value_low);
5930 GenerateAndConst(out_high, first_high, value_high);
5931 } else if (instruction->IsOr()) {
5932 GenerateOrrConst(out_low, first_low, value_low);
5933 GenerateOrrConst(out_high, first_high, value_high);
5934 } else {
5935 DCHECK(instruction->IsXor());
5936 GenerateEorConst(out_low, first_low, value_low);
5937 GenerateEorConst(out_high, first_high, value_high);
5938 }
5939 }
5940 return;
5941 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005942
5943 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005944 Register first_reg = first.AsRegister<Register>();
5945 ShifterOperand second_reg(second.AsRegister<Register>());
5946 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005947 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005948 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005949 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005950 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005951 } else {
5952 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005953 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005954 }
5955 } else {
5956 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005957 Register first_low = first.AsRegisterPairLow<Register>();
5958 Register first_high = first.AsRegisterPairHigh<Register>();
5959 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5960 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5961 Register out_low = out.AsRegisterPairLow<Register>();
5962 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005963 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005964 __ and_(out_low, first_low, second_low);
5965 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005966 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005967 __ orr(out_low, first_low, second_low);
5968 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005969 } else {
5970 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005971 __ eor(out_low, first_low, second_low);
5972 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005973 }
5974 }
5975}
5976
Roland Levillainc9285912015-12-18 10:38:42 +00005977void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
5978 Location out,
5979 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005980 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00005981 Register out_reg = out.AsRegister<Register>();
5982 if (kEmitCompilerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005983 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00005984 if (kUseBakerReadBarrier) {
5985 // Load with fast path based Baker's read barrier.
5986 // /* HeapReference<Object> */ out = *(out + offset)
5987 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005988 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00005989 } else {
5990 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005991 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00005992 // in the following move operation, as we will need it for the
5993 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005994 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00005995 // /* HeapReference<Object> */ out = *(out + offset)
5996 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005997 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00005998 }
5999 } else {
6000 // Plain load with no read barrier.
6001 // /* HeapReference<Object> */ out = *(out + offset)
6002 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6003 __ MaybeUnpoisonHeapReference(out_reg);
6004 }
6005}
6006
6007void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6008 Location out,
6009 Location obj,
6010 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006011 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006012 Register out_reg = out.AsRegister<Register>();
6013 Register obj_reg = obj.AsRegister<Register>();
6014 if (kEmitCompilerReadBarrier) {
6015 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006016 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006017 // Load with fast path based Baker's read barrier.
6018 // /* HeapReference<Object> */ out = *(obj + offset)
6019 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006020 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006021 } else {
6022 // Load with slow path based read barrier.
6023 // /* HeapReference<Object> */ out = *(obj + offset)
6024 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6025 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6026 }
6027 } else {
6028 // Plain load with no read barrier.
6029 // /* HeapReference<Object> */ out = *(obj + offset)
6030 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6031 __ MaybeUnpoisonHeapReference(out_reg);
6032 }
6033}
6034
6035void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6036 Location root,
6037 Register obj,
6038 uint32_t offset) {
6039 Register root_reg = root.AsRegister<Register>();
6040 if (kEmitCompilerReadBarrier) {
6041 if (kUseBakerReadBarrier) {
6042 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6043 // Baker's read barrier are used:
6044 //
6045 // root = obj.field;
6046 // if (Thread::Current()->GetIsGcMarking()) {
6047 // root = ReadBarrier::Mark(root)
6048 // }
6049
6050 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6051 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6052 static_assert(
6053 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6054 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6055 "have different sizes.");
6056 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6057 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6058 "have different sizes.");
6059
6060 // Slow path used to mark the GC root `root`.
6061 SlowPathCode* slow_path =
6062 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
6063 codegen_->AddSlowPath(slow_path);
6064
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006065 // IP = Thread::Current()->GetIsGcMarking()
Roland Levillainc9285912015-12-18 10:38:42 +00006066 __ LoadFromOffset(
6067 kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6068 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6069 __ Bind(slow_path->GetExitLabel());
6070 } else {
6071 // GC root loaded through a slow path for read barriers other
6072 // than Baker's.
6073 // /* GcRoot<mirror::Object>* */ root = obj + offset
6074 __ AddConstant(root_reg, obj, offset);
6075 // /* mirror::Object* */ root = root->Read()
6076 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6077 }
6078 } else {
6079 // Plain GC root load with no read barrier.
6080 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6081 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6082 // Note that GC roots are not affected by heap poisoning, thus we
6083 // do not have to unpoison `root_reg` here.
6084 }
6085}
6086
6087void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6088 Location ref,
6089 Register obj,
6090 uint32_t offset,
6091 Location temp,
6092 bool needs_null_check) {
6093 DCHECK(kEmitCompilerReadBarrier);
6094 DCHECK(kUseBakerReadBarrier);
6095
6096 // /* HeapReference<Object> */ ref = *(obj + offset)
6097 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01006098 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00006099 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006100 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006101}
6102
6103void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6104 Location ref,
6105 Register obj,
6106 uint32_t data_offset,
6107 Location index,
6108 Location temp,
6109 bool needs_null_check) {
6110 DCHECK(kEmitCompilerReadBarrier);
6111 DCHECK(kUseBakerReadBarrier);
6112
Roland Levillainbfea3352016-06-23 13:48:47 +01006113 static_assert(
6114 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6115 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006116 // /* HeapReference<Object> */ ref =
6117 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01006118 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00006119 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01006120 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00006121}
6122
6123void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6124 Location ref,
6125 Register obj,
6126 uint32_t offset,
6127 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01006128 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00006129 Location temp,
6130 bool needs_null_check) {
6131 DCHECK(kEmitCompilerReadBarrier);
6132 DCHECK(kUseBakerReadBarrier);
6133
6134 // In slow path based read barriers, the read barrier call is
6135 // inserted after the original load. However, in fast path based
6136 // Baker's read barriers, we need to perform the load of
6137 // mirror::Object::monitor_ *before* the original reference load.
6138 // This load-load ordering is required by the read barrier.
6139 // The fast path/slow path (for Baker's algorithm) should look like:
6140 //
6141 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6142 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6143 // HeapReference<Object> ref = *src; // Original reference load.
6144 // bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6145 // if (is_gray) {
6146 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6147 // }
6148 //
6149 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006150 // slightly more complex as it performs additional checks that we do
6151 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00006152
6153 Register ref_reg = ref.AsRegister<Register>();
6154 Register temp_reg = temp.AsRegister<Register>();
6155 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6156
6157 // /* int32_t */ monitor = obj->monitor_
6158 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6159 if (needs_null_check) {
6160 MaybeRecordImplicitNullCheck(instruction);
6161 }
6162 // /* LockWord */ lock_word = LockWord(monitor)
6163 static_assert(sizeof(LockWord) == sizeof(int32_t),
6164 "art::LockWord and int32_t have different sizes.");
6165 // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
6166 __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
6167 __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6168 static_assert(
6169 LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
6170 "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
6171
6172 // Introduce a dependency on the high bits of rb_state, which shall
6173 // be all zeroes, to prevent load-load reordering, and without using
6174 // a memory barrier (which would be more expensive).
6175 // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
6176 __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6177 // obj is unchanged by this operation, but its value now depends on
6178 // IP, which depends on temp_reg.
6179 __ add(obj, obj, ShifterOperand(IP));
6180
6181 // The actual reference load.
6182 if (index.IsValid()) {
Roland Levillainbfea3352016-06-23 13:48:47 +01006183 // Load types involving an "index": ArrayGet and
6184 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
6185 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00006186 if (index.IsConstant()) {
6187 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01006188 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006189 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6190 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01006191 // Handle the special case of the
6192 // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use
6193 // a register pair as index ("long offset"), of which only the low
6194 // part contains data.
6195 Register index_reg = index.IsRegisterPair()
6196 ? index.AsRegisterPairLow<Register>()
6197 : index.AsRegister<Register>();
6198 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00006199 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6200 }
6201 } else {
6202 // /* HeapReference<Object> */ ref = *(obj + offset)
6203 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6204 }
6205
6206 // Object* ref = ref_addr->AsMirrorPtr()
6207 __ MaybeUnpoisonHeapReference(ref_reg);
6208
6209 // Slow path used to mark the object `ref` when it is gray.
6210 SlowPathCode* slow_path =
6211 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
6212 AddSlowPath(slow_path);
6213
6214 // if (rb_state == ReadBarrier::gray_ptr_)
6215 // ref = ReadBarrier::Mark(ref);
6216 __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
6217 __ b(slow_path->GetEntryLabel(), EQ);
6218 __ Bind(slow_path->GetExitLabel());
6219}
6220
6221void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6222 Location out,
6223 Location ref,
6224 Location obj,
6225 uint32_t offset,
6226 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006227 DCHECK(kEmitCompilerReadBarrier);
6228
Roland Levillainc9285912015-12-18 10:38:42 +00006229 // Insert a slow path based read barrier *after* the reference load.
6230 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006231 // If heap poisoning is enabled, the unpoisoning of the loaded
6232 // reference will be carried out by the runtime within the slow
6233 // path.
6234 //
6235 // Note that `ref` currently does not get unpoisoned (when heap
6236 // poisoning is enabled), which is alright as the `ref` argument is
6237 // not used by the artReadBarrierSlow entry point.
6238 //
6239 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6240 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6241 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6242 AddSlowPath(slow_path);
6243
Roland Levillain3b359c72015-11-17 19:35:12 +00006244 __ b(slow_path->GetEntryLabel());
6245 __ Bind(slow_path->GetExitLabel());
6246}
6247
Roland Levillainc9285912015-12-18 10:38:42 +00006248void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6249 Location out,
6250 Location ref,
6251 Location obj,
6252 uint32_t offset,
6253 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006254 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00006255 // Baker's read barriers shall be handled by the fast path
6256 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6257 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006258 // If heap poisoning is enabled, unpoisoning will be taken care of
6259 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00006260 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00006261 } else if (kPoisonHeapReferences) {
6262 __ UnpoisonHeapReference(out.AsRegister<Register>());
6263 }
6264}
6265
Roland Levillainc9285912015-12-18 10:38:42 +00006266void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6267 Location out,
6268 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006269 DCHECK(kEmitCompilerReadBarrier);
6270
Roland Levillainc9285912015-12-18 10:38:42 +00006271 // Insert a slow path based read barrier *after* the GC root load.
6272 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006273 // Note that GC roots are not affected by heap poisoning, so we do
6274 // not need to do anything special for this here.
6275 SlowPathCode* slow_path =
6276 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6277 AddSlowPath(slow_path);
6278
Roland Levillain3b359c72015-11-17 19:35:12 +00006279 __ b(slow_path->GetEntryLabel());
6280 __ Bind(slow_path->GetExitLabel());
6281}
6282
Vladimir Markodc151b22015-10-15 18:02:30 +01006283HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6284 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6285 MethodReference target_method) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006286 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6287 // We disable pc-relative load when there is an irreducible loop, as the optimization
6288 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006289 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6290 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006291 if (GetGraph()->HasIrreducibleLoops() &&
6292 (dispatch_info.method_load_kind ==
6293 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6294 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6295 }
6296
6297 if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
Vladimir Markodc151b22015-10-15 18:02:30 +01006298 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6299 if (&outer_dex_file != target_method.dex_file) {
6300 // Calls across dex files are more likely to exceed the available BL range,
6301 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6302 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6303 (desired_dispatch_info.method_load_kind ==
6304 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6305 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6306 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6307 return HInvokeStaticOrDirect::DispatchInfo {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006308 dispatch_info.method_load_kind,
Vladimir Markodc151b22015-10-15 18:02:30 +01006309 code_ptr_location,
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006310 dispatch_info.method_load_data,
Vladimir Markodc151b22015-10-15 18:02:30 +01006311 0u
6312 };
6313 }
6314 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006315 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01006316}
6317
Vladimir Markob4536b72015-11-24 13:45:23 +00006318Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6319 Register temp) {
6320 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6321 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6322 if (!invoke->GetLocations()->Intrinsified()) {
6323 return location.AsRegister<Register>();
6324 }
6325 // For intrinsics we allow any location, so it may be on the stack.
6326 if (!location.IsRegister()) {
6327 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6328 return temp;
6329 }
6330 // For register locations, check if the register was saved. If so, get it from the stack.
6331 // Note: There is a chance that the register was saved but not overwritten, so we could
6332 // save one load. However, since this is just an intrinsic slow path we prefer this
6333 // simple and more robust approach rather that trying to determine if that's the case.
6334 SlowPathCode* slow_path = GetCurrentSlowPath();
6335 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6336 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6337 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6338 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6339 return temp;
6340 }
6341 return location.AsRegister<Register>();
6342}
6343
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006344void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006345 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006346 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006347 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6348 // LR = code address from literal pool with link-time patch.
6349 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006350 break;
6351 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6352 // LR = invoke->GetDirectCodePtr();
6353 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006354 break;
6355 default:
6356 break;
6357 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006358
Vladimir Marko58155012015-08-19 12:49:41 +00006359 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6360 switch (invoke->GetMethodLoadKind()) {
6361 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6362 // temp = thread->string_init_entrypoint
6363 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6364 break;
6365 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006366 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006367 break;
6368 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6369 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6370 break;
6371 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6372 __ LoadLiteral(temp.AsRegister<Register>(),
6373 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6374 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006375 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6376 HArmDexCacheArraysBase* base =
6377 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6378 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6379 temp.AsRegister<Register>());
6380 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6381 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6382 break;
6383 }
Vladimir Marko58155012015-08-19 12:49:41 +00006384 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006385 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006386 Register method_reg;
6387 Register reg = temp.AsRegister<Register>();
6388 if (current_method.IsRegister()) {
6389 method_reg = current_method.AsRegister<Register>();
6390 } else {
6391 DCHECK(invoke->GetLocations()->Intrinsified());
6392 DCHECK(!current_method.IsValid());
6393 method_reg = reg;
6394 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6395 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006396 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6397 __ LoadFromOffset(kLoadWord,
6398 reg,
6399 method_reg,
6400 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01006401 // temp = temp[index_in_cache];
6402 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
6403 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00006404 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6405 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006406 }
Vladimir Marko58155012015-08-19 12:49:41 +00006407 }
6408
6409 switch (invoke->GetCodePtrLocation()) {
6410 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6411 __ bl(GetFrameEntryLabel());
6412 break;
6413 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006414 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006415 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006416 // Arbitrarily branch to the BL itself, override at link time.
6417 __ bl(&relative_call_patches_.back().label);
6418 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006419 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6420 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6421 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006422 // LR()
6423 __ blx(LR);
6424 break;
6425 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6426 // LR = callee_method->entry_point_from_quick_compiled_code_
6427 __ LoadFromOffset(
6428 kLoadWord, LR, callee_method.AsRegister<Register>(),
6429 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6430 // LR()
6431 __ blx(LR);
6432 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006433 }
6434
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006435 DCHECK(!IsLeafMethod());
6436}
6437
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006438void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6439 Register temp = temp_location.AsRegister<Register>();
6440 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6441 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006442
6443 // Use the calling convention instead of the location of the receiver, as
6444 // intrinsics may have put the receiver in a different register. In the intrinsics
6445 // slow path, the arguments have been moved to the right place, so here we are
6446 // guaranteed that the receiver is the first register of the calling convention.
6447 InvokeDexCallingConvention calling_convention;
6448 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006449 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006450 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006451 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006452 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006453 // Instead of simply (possibly) unpoisoning `temp` here, we should
6454 // emit a read barrier for the previous class reference load.
6455 // However this is not required in practice, as this is an
6456 // intermediate/temporary reference and because the current
6457 // concurrent copying collector keeps the from-space memory
6458 // intact/accessible until the end of the marking phase (the
6459 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006460 __ MaybeUnpoisonHeapReference(temp);
6461 // temp = temp->GetMethodAt(method_offset);
6462 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6463 kArmWordSize).Int32Value();
6464 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6465 // LR = temp->GetEntryPoint();
6466 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6467 // LR();
6468 __ blx(LR);
6469}
6470
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006471CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6472 const DexFile& dex_file, uint32_t string_index) {
6473 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6474}
6475
6476CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6477 const DexFile& dex_file, uint32_t element_offset) {
6478 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6479}
6480
6481CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6482 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6483 patches->emplace_back(dex_file, offset_or_index);
6484 return &patches->back();
6485}
6486
6487Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6488 uint32_t string_index) {
6489 return boot_image_string_patches_.GetOrCreate(
6490 StringReference(&dex_file, string_index),
6491 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6492}
6493
6494Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6495 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6496 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6497 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6498}
6499
6500Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6501 return DeduplicateUint32Literal(address, &uint32_literals_);
6502}
6503
Vladimir Marko58155012015-08-19 12:49:41 +00006504void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6505 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006506 size_t size =
6507 method_patches_.size() +
6508 call_patches_.size() +
6509 relative_call_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006510 /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6511 boot_image_string_patches_.size() +
6512 /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
6513 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006514 linker_patches->reserve(size);
6515 for (const auto& entry : method_patches_) {
6516 const MethodReference& target_method = entry.first;
6517 Literal* literal = entry.second;
6518 DCHECK(literal->GetLabel()->IsBound());
6519 uint32_t literal_offset = literal->GetLabel()->Position();
6520 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6521 target_method.dex_file,
6522 target_method.dex_method_index));
6523 }
6524 for (const auto& entry : call_patches_) {
6525 const MethodReference& target_method = entry.first;
6526 Literal* literal = entry.second;
6527 DCHECK(literal->GetLabel()->IsBound());
6528 uint32_t literal_offset = literal->GetLabel()->Position();
6529 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6530 target_method.dex_file,
6531 target_method.dex_method_index));
6532 }
6533 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6534 uint32_t literal_offset = info.label.Position();
6535 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6536 info.target_method.dex_file,
6537 info.target_method.dex_method_index));
6538 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006539 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6540 const DexFile& dex_file = info.target_dex_file;
6541 size_t base_element_offset = info.offset_or_index;
6542 DCHECK(info.add_pc_label.IsBound());
6543 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006544 // Add MOVW patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006545 DCHECK(info.movw_label.IsBound());
6546 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006547 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6548 &dex_file,
6549 add_pc_offset,
6550 base_element_offset));
6551 // Add MOVT patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006552 DCHECK(info.movt_label.IsBound());
6553 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006554 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6555 &dex_file,
6556 add_pc_offset,
6557 base_element_offset));
6558 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006559 for (const auto& entry : boot_image_string_patches_) {
6560 const StringReference& target_string = entry.first;
6561 Literal* literal = entry.second;
6562 DCHECK(literal->GetLabel()->IsBound());
6563 uint32_t literal_offset = literal->GetLabel()->Position();
6564 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6565 target_string.dex_file,
6566 target_string.string_index));
6567 }
6568 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6569 const DexFile& dex_file = info.target_dex_file;
6570 uint32_t string_index = info.offset_or_index;
6571 DCHECK(info.add_pc_label.IsBound());
6572 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6573 // Add MOVW patch.
6574 DCHECK(info.movw_label.IsBound());
6575 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6576 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6577 &dex_file,
6578 add_pc_offset,
6579 string_index));
6580 // Add MOVT patch.
6581 DCHECK(info.movt_label.IsBound());
6582 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6583 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6584 &dex_file,
6585 add_pc_offset,
6586 string_index));
6587 }
6588 for (const auto& entry : boot_image_address_patches_) {
6589 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6590 Literal* literal = entry.second;
6591 DCHECK(literal->GetLabel()->IsBound());
6592 uint32_t literal_offset = literal->GetLabel()->Position();
6593 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6594 }
6595}
6596
6597Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6598 return map->GetOrCreate(
6599 value,
6600 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00006601}
6602
6603Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6604 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006605 return map->GetOrCreate(
6606 target_method,
6607 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00006608}
6609
6610Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6611 return DeduplicateMethodLiteral(target_method, &method_patches_);
6612}
6613
6614Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6615 return DeduplicateMethodLiteral(target_method, &call_patches_);
6616}
6617
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03006618void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6619 LocationSummary* locations =
6620 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6621 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6622 Location::RequiresRegister());
6623 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6624 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6625 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6626}
6627
6628void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6629 LocationSummary* locations = instr->GetLocations();
6630 Register res = locations->Out().AsRegister<Register>();
6631 Register accumulator =
6632 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6633 Register mul_left =
6634 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6635 Register mul_right =
6636 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6637
6638 if (instr->GetOpKind() == HInstruction::kAdd) {
6639 __ mla(res, mul_left, mul_right, accumulator);
6640 } else {
6641 __ mls(res, mul_left, mul_right, accumulator);
6642 }
6643}
6644
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006645void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006646 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006647 LOG(FATAL) << "Unreachable";
6648}
6649
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006650void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006651 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006652 LOG(FATAL) << "Unreachable";
6653}
6654
Mark Mendellfe57faa2015-09-18 09:26:15 -04006655// Simple implementation of packed switch - generate cascaded compare/jumps.
6656void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6657 LocationSummary* locations =
6658 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6659 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006660 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006661 codegen_->GetAssembler()->IsThumb()) {
6662 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6663 if (switch_instr->GetStartValue() != 0) {
6664 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6665 }
6666 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006667}
6668
6669void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6670 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006671 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006672 LocationSummary* locations = switch_instr->GetLocations();
6673 Register value_reg = locations->InAt(0).AsRegister<Register>();
6674 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6675
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006676 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006677 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006678 Register temp_reg = IP;
6679 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6680 // the immediate, because IP is used as the destination register. For the other
6681 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6682 // and they can be encoded in the instruction without making use of IP register.
6683 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6684
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006685 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006686 // Jump to successors[0] if value == lower_bound.
6687 __ b(codegen_->GetLabelOf(successors[0]), EQ);
6688 int32_t last_index = 0;
6689 for (; num_entries - last_index > 2; last_index += 2) {
6690 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6691 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6692 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6693 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6694 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6695 }
6696 if (num_entries - last_index == 2) {
6697 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00006698 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006699 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006700 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006701
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006702 // And the default for any other value.
6703 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6704 __ b(codegen_->GetLabelOf(default_block));
6705 }
6706 } else {
6707 // Create a table lookup.
6708 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6709
6710 // Materialize a pointer to the switch table
6711 std::vector<Label*> labels(num_entries);
6712 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6713 for (uint32_t i = 0; i < num_entries; i++) {
6714 labels[i] = codegen_->GetLabelOf(successors[i]);
6715 }
6716 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6717
6718 // Remove the bias.
6719 Register key_reg;
6720 if (lower_bound != 0) {
6721 key_reg = locations->GetTemp(1).AsRegister<Register>();
6722 __ AddConstant(key_reg, value_reg, -lower_bound);
6723 } else {
6724 key_reg = value_reg;
6725 }
6726
6727 // Check whether the value is in the table, jump to default block if not.
6728 __ CmpConstant(key_reg, num_entries - 1);
6729 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6730
6731 // Load the displacement from the table.
6732 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6733
6734 // Dispatch is a direct add to the PC (for Thumb2).
6735 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006736 }
6737}
6738
Vladimir Markob4536b72015-11-24 13:45:23 +00006739void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6740 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6741 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00006742}
6743
6744void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6745 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006746 CodeGeneratorARM::PcRelativePatchInfo* labels =
6747 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00006748 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006749 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006750 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006751 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006752 __ BindTrackedLabel(&labels->add_pc_label);
6753 __ add(base_reg, base_reg, ShifterOperand(PC));
6754}
6755
Andreas Gampe85b62f22015-09-09 13:15:38 -07006756void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6757 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00006758 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07006759 return;
6760 }
6761
6762 DCHECK_NE(type, Primitive::kPrimVoid);
6763
6764 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6765 if (return_loc.Equals(trg)) {
6766 return;
6767 }
6768
6769 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6770 // with the last branch.
6771 if (type == Primitive::kPrimLong) {
6772 HParallelMove parallel_move(GetGraph()->GetArena());
6773 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6774 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6775 GetMoveResolver()->EmitNativeCode(&parallel_move);
6776 } else if (type == Primitive::kPrimDouble) {
6777 HParallelMove parallel_move(GetGraph()->GetArena());
6778 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6779 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6780 GetMoveResolver()->EmitNativeCode(&parallel_move);
6781 } else {
6782 // Let the parallel move resolver take care of all of this.
6783 HParallelMove parallel_move(GetGraph()->GetArena());
6784 parallel_move.AddMove(return_loc, trg, type, nullptr);
6785 GetMoveResolver()->EmitNativeCode(&parallel_move);
6786 }
6787}
6788
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006789void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
6790 LocationSummary* locations =
6791 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6792 locations->SetInAt(0, Location::RequiresRegister());
6793 locations->SetOut(Location::RequiresRegister());
6794}
6795
6796void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
6797 LocationSummary* locations = instruction->GetLocations();
6798 uint32_t method_offset = 0;
Vladimir Markoa1de9182016-02-25 11:37:38 +00006799 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006800 method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6801 instruction->GetIndex(), kArmPointerSize).SizeValue();
6802 } else {
Nelli Kimbadee982016-05-13 13:08:53 +03006803 __ LoadFromOffset(kLoadWord, locations->Out().AsRegister<Register>(),
6804 locations->InAt(0).AsRegister<Register>(),
6805 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
6806 method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity50706432016-06-14 11:31:04 -07006807 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006808 }
6809 __ LoadFromOffset(kLoadWord,
6810 locations->Out().AsRegister<Register>(),
6811 locations->InAt(0).AsRegister<Register>(),
6812 method_offset);
6813}
6814
Roland Levillain4d027112015-07-01 15:41:14 +01006815#undef __
6816#undef QUICK_ENTRY_POINT
6817
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006818} // namespace arm
6819} // namespace art