blob: 98577d67ea2cbac74a5de98108da3567fa203395 [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
Roland Levillain62a46b22015-06-01 18:24:13 +010062#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010063#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064
Andreas Gampe85b62f22015-09-09 13:15:38 -070065class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000067 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068
Alexandre Rames67555f72014-11-18 10:55:16 +000069 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010070 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010071 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000072 if (instruction_->CanThrowIntoCatchBlock()) {
73 // Live registers will be restored in the catch block if caught.
74 SaveLiveRegisters(codegen, instruction_->GetLocations());
75 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010076 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000077 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +000078 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +010079 }
80
Alexandre Rames8158f282015-08-07 10:26:17 +010081 bool IsFatal() const OVERRIDE { return true; }
82
Alexandre Rames9931f312015-06-19 14:47:01 +010083 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
84
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +010086 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
87};
88
Andreas Gampe85b62f22015-09-09 13:15:38 -070089class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000090 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000091 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCode(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +000092
Alexandre Rames67555f72014-11-18 10:55:16 +000093 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000094 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
95 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000096 if (instruction_->CanThrowIntoCatchBlock()) {
97 // Live registers will be restored in the catch block if caught.
98 SaveLiveRegisters(codegen, instruction_->GetLocations());
99 }
Calin Juravled0d48522014-11-04 16:40:20 +0000100 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000101 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000102 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000103 }
104
Alexandre Rames8158f282015-08-07 10:26:17 +0100105 bool IsFatal() const OVERRIDE { return true; }
106
Alexandre Rames9931f312015-06-19 14:47:01 +0100107 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
108
Calin Juravled0d48522014-11-04 16:40:20 +0000109 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000110 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
111};
112
Andreas Gampe85b62f22015-09-09 13:15:38 -0700113class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000114 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000115 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000116 : SlowPathCode(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000117
Alexandre Rames67555f72014-11-18 10:55:16 +0000118 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100119 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000120 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000121 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100122 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000123 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000124 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000125 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100126 if (successor_ == nullptr) {
127 __ b(GetReturnLabel());
128 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100129 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100130 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000131 }
132
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 Label* GetReturnLabel() {
134 DCHECK(successor_ == nullptr);
135 return &return_label_;
136 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100138 HBasicBlock* GetSuccessor() const {
139 return successor_;
140 }
141
Alexandre Rames9931f312015-06-19 14:47:01 +0100142 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
143
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000144 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 // If not null, the block to branch to after the suspend check.
146 HBasicBlock* const successor_;
147
148 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000149 Label return_label_;
150
151 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
152};
153
Andreas Gampe85b62f22015-09-09 13:15:38 -0700154class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100155 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100156 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000157 : SlowPathCode(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100158
Alexandre Rames67555f72014-11-18 10:55:16 +0000159 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100160 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100161 LocationSummary* locations = instruction_->GetLocations();
162
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100163 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000164 if (instruction_->CanThrowIntoCatchBlock()) {
165 // Live registers will be restored in the catch block if caught.
166 SaveLiveRegisters(codegen, instruction_->GetLocations());
167 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000168 // We're moving two locations to locations that could overlap, so we need a parallel
169 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100170 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000171 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100172 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000173 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100174 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100175 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100176 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
177 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100178 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000179 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000180 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100181 }
182
Alexandre Rames8158f282015-08-07 10:26:17 +0100183 bool IsFatal() const OVERRIDE { return true; }
184
Alexandre Rames9931f312015-06-19 14:47:01 +0100185 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
186
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100188 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
189};
190
Andreas Gampe85b62f22015-09-09 13:15:38 -0700191class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100192 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000193 LoadClassSlowPathARM(HLoadClass* cls,
194 HInstruction* at,
195 uint32_t dex_pc,
196 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000197 : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000198 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
199 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100200
Alexandre Rames67555f72014-11-18 10:55:16 +0000201 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000202 LocationSummary* locations = at_->GetLocations();
203
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
205 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000206 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 int32_t entry_point_offset = do_clinit_
211 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
212 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000213 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000214 if (do_clinit_) {
215 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
216 } else {
217 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
218 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219
220 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000221 Location out = locations->Out();
222 if (out.IsValid()) {
223 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000224 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
225 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000226 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100227 __ b(GetExitLabel());
228 }
229
Alexandre Rames9931f312015-06-19 14:47:01 +0100230 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
231
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100232 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000233 // The class this slow path will load.
234 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100235
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000236 // The instruction where this slow path is happening.
237 // (Might be the load class or an initialization check).
238 HInstruction* const at_;
239
240 // The dex PC of `at_`.
241 const uint32_t dex_pc_;
242
243 // Whether to initialize the class.
244 const bool do_clinit_;
245
246 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100247};
248
Andreas Gampe85b62f22015-09-09 13:15:38 -0700249class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000250 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000251 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000252
Alexandre Rames67555f72014-11-18 10:55:16 +0000253 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000254 LocationSummary* locations = instruction_->GetLocations();
255 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
256
257 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
258 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000259 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000260
261 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000262 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
263 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000264 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000265 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000266 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000267 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
268
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000269 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000270 __ b(GetExitLabel());
271 }
272
Alexandre Rames9931f312015-06-19 14:47:01 +0100273 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
274
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000275 private:
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000276 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
277};
278
Andreas Gampe85b62f22015-09-09 13:15:38 -0700279class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000281 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
David Srbecky9cd6d372016-02-09 15:24:47 +0000282 : SlowPathCode(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000283
Alexandre Rames67555f72014-11-18 10:55:16 +0000284 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100286 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
287 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000288 DCHECK(instruction_->IsCheckCast()
289 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000290
291 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
292 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000293
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000294 if (!is_fatal_) {
295 SaveLiveRegisters(codegen, locations);
296 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000297
298 // We're moving two locations to locations that could overlap, so we need a parallel
299 // move resolver.
300 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000301 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100302 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000303 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100304 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100305 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100306 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
307 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000308
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000309 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100310 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
311 instruction_,
312 instruction_->GetDexPc(),
313 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000314 CheckEntrypointTypes<
315 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000316 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
317 } else {
318 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100319 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
320 instruction_,
321 instruction_->GetDexPc(),
322 this);
Roland Levillain3b359c72015-11-17 19:35:12 +0000323 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000324 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000325
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000326 if (!is_fatal_) {
327 RestoreLiveRegisters(codegen, locations);
328 __ b(GetExitLabel());
329 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000330 }
331
Alexandre Rames9931f312015-06-19 14:47:01 +0100332 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
333
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000334 bool IsFatal() const OVERRIDE { return is_fatal_; }
335
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000336 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000337 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000338
339 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
340};
341
Andreas Gampe85b62f22015-09-09 13:15:38 -0700342class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700343 public:
Aart Bik42249c32016-01-07 15:33:50 -0800344 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000345 : SlowPathCode(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700346
347 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800348 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700349 __ Bind(GetEntryLabel());
350 SaveLiveRegisters(codegen, instruction_->GetLocations());
Aart Bik42249c32016-01-07 15:33:50 -0800351 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
352 instruction_,
353 instruction_->GetDexPc(),
354 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000355 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700356 }
357
Alexandre Rames9931f312015-06-19 14:47:01 +0100358 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
359
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700360 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700361 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
362};
363
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100364class ArraySetSlowPathARM : public SlowPathCode {
365 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000366 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100367
368 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
369 LocationSummary* locations = instruction_->GetLocations();
370 __ Bind(GetEntryLabel());
371 SaveLiveRegisters(codegen, locations);
372
373 InvokeRuntimeCallingConvention calling_convention;
374 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
375 parallel_move.AddMove(
376 locations->InAt(0),
377 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
378 Primitive::kPrimNot,
379 nullptr);
380 parallel_move.AddMove(
381 locations->InAt(1),
382 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
383 Primitive::kPrimInt,
384 nullptr);
385 parallel_move.AddMove(
386 locations->InAt(2),
387 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
388 Primitive::kPrimNot,
389 nullptr);
390 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
391
392 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
393 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
394 instruction_,
395 instruction_->GetDexPc(),
396 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000397 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100398 RestoreLiveRegisters(codegen, locations);
399 __ b(GetExitLabel());
400 }
401
402 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
403
404 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100405 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
406};
407
Roland Levillainc9285912015-12-18 10:38:42 +0000408// Slow path marking an object during a read barrier.
409class ReadBarrierMarkSlowPathARM : public SlowPathCode {
410 public:
411 ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location out, Location obj)
David Srbecky9cd6d372016-02-09 15:24:47 +0000412 : SlowPathCode(instruction), out_(out), obj_(obj) {
Roland Levillainc9285912015-12-18 10:38:42 +0000413 DCHECK(kEmitCompilerReadBarrier);
414 }
415
416 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
417
418 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
419 LocationSummary* locations = instruction_->GetLocations();
420 Register reg_out = out_.AsRegister<Register>();
421 DCHECK(locations->CanCall());
422 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
423 DCHECK(instruction_->IsInstanceFieldGet() ||
424 instruction_->IsStaticFieldGet() ||
425 instruction_->IsArrayGet() ||
426 instruction_->IsLoadClass() ||
427 instruction_->IsLoadString() ||
428 instruction_->IsInstanceOf() ||
429 instruction_->IsCheckCast())
430 << "Unexpected instruction in read barrier marking slow path: "
431 << instruction_->DebugName();
432
433 __ Bind(GetEntryLabel());
434 SaveLiveRegisters(codegen, locations);
435
436 InvokeRuntimeCallingConvention calling_convention;
437 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
438 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
439 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
440 instruction_,
441 instruction_->GetDexPc(),
442 this);
443 CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
444 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
445
446 RestoreLiveRegisters(codegen, locations);
447 __ b(GetExitLabel());
448 }
449
450 private:
Roland Levillainc9285912015-12-18 10:38:42 +0000451 const Location out_;
452 const Location obj_;
453
454 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
455};
456
Roland Levillain3b359c72015-11-17 19:35:12 +0000457// Slow path generating a read barrier for a heap reference.
458class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
459 public:
460 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
461 Location out,
462 Location ref,
463 Location obj,
464 uint32_t offset,
465 Location index)
David Srbecky9cd6d372016-02-09 15:24:47 +0000466 : SlowPathCode(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +0000467 out_(out),
468 ref_(ref),
469 obj_(obj),
470 offset_(offset),
471 index_(index) {
472 DCHECK(kEmitCompilerReadBarrier);
473 // If `obj` is equal to `out` or `ref`, it means the initial object
474 // has been overwritten by (or after) the heap object reference load
475 // to be instrumented, e.g.:
476 //
477 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +0000478 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +0000479 //
480 // In that case, we have lost the information about the original
481 // object, and the emitted read barrier cannot work properly.
482 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
483 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
484 }
485
486 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
487 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
488 LocationSummary* locations = instruction_->GetLocations();
489 Register reg_out = out_.AsRegister<Register>();
490 DCHECK(locations->CanCall());
491 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
492 DCHECK(!instruction_->IsInvoke() ||
493 (instruction_->IsInvokeStaticOrDirect() &&
Roland Levillainc9285912015-12-18 10:38:42 +0000494 instruction_->GetLocations()->Intrinsified()))
495 << "Unexpected instruction in read barrier for heap reference slow path: "
496 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000497
498 __ Bind(GetEntryLabel());
499 SaveLiveRegisters(codegen, locations);
500
501 // We may have to change the index's value, but as `index_` is a
502 // constant member (like other "inputs" of this slow path),
503 // introduce a copy of it, `index`.
504 Location index = index_;
505 if (index_.IsValid()) {
506 // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
507 if (instruction_->IsArrayGet()) {
508 // Compute the actual memory offset and store it in `index`.
509 Register index_reg = index_.AsRegister<Register>();
510 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
511 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
512 // We are about to change the value of `index_reg` (see the
513 // calls to art::arm::Thumb2Assembler::Lsl and
514 // art::arm::Thumb2Assembler::AddConstant below), but it has
515 // not been saved by the previous call to
516 // art::SlowPathCode::SaveLiveRegisters, as it is a
517 // callee-save register --
518 // art::SlowPathCode::SaveLiveRegisters does not consider
519 // callee-save registers, as it has been designed with the
520 // assumption that callee-save registers are supposed to be
521 // handled by the called function. So, as a callee-save
522 // register, `index_reg` _would_ eventually be saved onto
523 // the stack, but it would be too late: we would have
524 // changed its value earlier. Therefore, we manually save
525 // it here into another freely available register,
526 // `free_reg`, chosen of course among the caller-save
527 // registers (as a callee-save `free_reg` register would
528 // exhibit the same problem).
529 //
530 // Note we could have requested a temporary register from
531 // the register allocator instead; but we prefer not to, as
532 // this is a slow path, and we know we can find a
533 // caller-save register that is available.
534 Register free_reg = FindAvailableCallerSaveRegister(codegen);
535 __ Mov(free_reg, index_reg);
536 index_reg = free_reg;
537 index = Location::RegisterLocation(index_reg);
538 } else {
539 // The initial register stored in `index_` has already been
540 // saved in the call to art::SlowPathCode::SaveLiveRegisters
541 // (as it is not a callee-save register), so we can freely
542 // use it.
543 }
544 // Shifting the index value contained in `index_reg` by the scale
545 // factor (2) cannot overflow in practice, as the runtime is
546 // unable to allocate object arrays with a size larger than
547 // 2^26 - 1 (that is, 2^28 - 4 bytes).
548 __ Lsl(index_reg, index_reg, TIMES_4);
549 static_assert(
550 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
551 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
552 __ AddConstant(index_reg, index_reg, offset_);
553 } else {
554 DCHECK(instruction_->IsInvoke());
555 DCHECK(instruction_->GetLocations()->Intrinsified());
556 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
557 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
558 << instruction_->AsInvoke()->GetIntrinsic();
559 DCHECK_EQ(offset_, 0U);
560 DCHECK(index_.IsRegisterPair());
561 // UnsafeGet's offset location is a register pair, the low
562 // part contains the correct offset.
563 index = index_.ToLow();
564 }
565 }
566
567 // We're moving two or three locations to locations that could
568 // overlap, so we need a parallel move resolver.
569 InvokeRuntimeCallingConvention calling_convention;
570 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
571 parallel_move.AddMove(ref_,
572 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
573 Primitive::kPrimNot,
574 nullptr);
575 parallel_move.AddMove(obj_,
576 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
577 Primitive::kPrimNot,
578 nullptr);
579 if (index.IsValid()) {
580 parallel_move.AddMove(index,
581 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
582 Primitive::kPrimInt,
583 nullptr);
584 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
585 } else {
586 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
587 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
588 }
589 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
590 instruction_,
591 instruction_->GetDexPc(),
592 this);
593 CheckEntrypointTypes<
594 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
595 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
596
597 RestoreLiveRegisters(codegen, locations);
598 __ b(GetExitLabel());
599 }
600
601 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
602
603 private:
604 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
605 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
606 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
607 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
608 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
609 return static_cast<Register>(i);
610 }
611 }
612 // We shall never fail to find a free caller-save register, as
613 // there are more than two core caller-save registers on ARM
614 // (meaning it is possible to find one which is different from
615 // `ref` and `obj`).
616 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
617 LOG(FATAL) << "Could not find a free caller-save register";
618 UNREACHABLE();
619 }
620
Roland Levillain3b359c72015-11-17 19:35:12 +0000621 const Location out_;
622 const Location ref_;
623 const Location obj_;
624 const uint32_t offset_;
625 // An additional location containing an index to an array.
626 // Only used for HArrayGet and the UnsafeGetObject &
627 // UnsafeGetObjectVolatile intrinsics.
628 const Location index_;
629
630 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
631};
632
633// Slow path generating a read barrier for a GC root.
634class ReadBarrierForRootSlowPathARM : public SlowPathCode {
635 public:
636 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
David Srbecky9cd6d372016-02-09 15:24:47 +0000637 : SlowPathCode(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +0000638 DCHECK(kEmitCompilerReadBarrier);
639 }
Roland Levillain3b359c72015-11-17 19:35:12 +0000640
641 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
642 LocationSummary* locations = instruction_->GetLocations();
643 Register reg_out = out_.AsRegister<Register>();
644 DCHECK(locations->CanCall());
645 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +0000646 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
647 << "Unexpected instruction in read barrier for GC root slow path: "
648 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +0000649
650 __ Bind(GetEntryLabel());
651 SaveLiveRegisters(codegen, locations);
652
653 InvokeRuntimeCallingConvention calling_convention;
654 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
655 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
656 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
657 instruction_,
658 instruction_->GetDexPc(),
659 this);
660 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
661 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
662
663 RestoreLiveRegisters(codegen, locations);
664 __ b(GetExitLabel());
665 }
666
667 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
668
669 private:
Roland Levillain3b359c72015-11-17 19:35:12 +0000670 const Location out_;
671 const Location root_;
672
673 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
674};
675
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000676#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100677#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700678
Aart Bike9f37602015-10-09 11:15:55 -0700679inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700680 switch (cond) {
681 case kCondEQ: return EQ;
682 case kCondNE: return NE;
683 case kCondLT: return LT;
684 case kCondLE: return LE;
685 case kCondGT: return GT;
686 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700687 case kCondB: return LO;
688 case kCondBE: return LS;
689 case kCondA: return HI;
690 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700691 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100692 LOG(FATAL) << "Unreachable";
693 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700694}
695
Aart Bike9f37602015-10-09 11:15:55 -0700696// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100697inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700698 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100699 case kCondEQ: return EQ;
700 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700701 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100702 case kCondLT: return LO;
703 case kCondLE: return LS;
704 case kCondGT: return HI;
705 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700706 // Unsigned remain unchanged.
707 case kCondB: return LO;
708 case kCondBE: return LS;
709 case kCondA: return HI;
710 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700711 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100712 LOG(FATAL) << "Unreachable";
713 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700714}
715
Vladimir Markod6e069b2016-01-18 11:11:01 +0000716inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
717 // The ARM condition codes can express all the necessary branches, see the
718 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
719 // There is no dex instruction or HIR that would need the missing conditions
720 // "equal or unordered" or "not equal".
721 switch (cond) {
722 case kCondEQ: return EQ;
723 case kCondNE: return NE /* unordered */;
724 case kCondLT: return gt_bias ? CC : LT /* unordered */;
725 case kCondLE: return gt_bias ? LS : LE /* unordered */;
726 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
727 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
728 default:
729 LOG(FATAL) << "UNREACHABLE";
730 UNREACHABLE();
731 }
732}
733
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100734void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100735 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100736}
737
738void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100739 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100740}
741
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100742size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
743 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
744 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100745}
746
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100747size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
748 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
749 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100750}
751
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000752size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
753 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
754 return kArmWordSize;
755}
756
757size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
758 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
759 return kArmWordSize;
760}
761
Calin Juravle34166012014-12-19 17:22:29 +0000762CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000763 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100764 const CompilerOptions& compiler_options,
765 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000766 : CodeGenerator(graph,
767 kNumberOfCoreRegisters,
768 kNumberOfSRegisters,
769 kNumberOfRegisterPairs,
770 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
771 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000772 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
773 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100774 compiler_options,
775 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100776 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100777 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100778 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100779 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000780 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000781 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000782 uint32_literals_(std::less<uint32_t>(),
783 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko5233f932015-09-29 19:01:15 +0100784 method_patches_(MethodReferenceComparator(),
785 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
786 call_patches_(MethodReferenceComparator(),
787 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markob4536b72015-11-24 13:45:23 +0000788 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000789 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
790 boot_image_string_patches_(StringReferenceValueComparator(),
791 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
792 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
793 boot_image_address_patches_(std::less<uint32_t>(),
794 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700795 // Always save the LR register to mimic Quick.
796 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100797}
798
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000799void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
800 // Ensure that we fix up branches and literal loads and emit the literal pool.
801 __ FinalizeCode();
802
803 // Adjust native pc offsets in stack maps.
804 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
805 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
806 uint32_t new_position = __ GetAdjustedPosition(old_position);
807 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
808 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100809 // Adjust pc offsets for the disassembly information.
810 if (disasm_info_ != nullptr) {
811 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
812 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
813 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
814 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
815 it.second.start = __ GetAdjustedPosition(it.second.start);
816 it.second.end = __ GetAdjustedPosition(it.second.end);
817 }
818 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
819 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
820 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
821 }
822 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000823
824 CodeGenerator::Finalize(allocator);
825}
826
David Brazdil58282f42016-01-14 12:45:10 +0000827void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100828 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100829 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100830
831 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100832 blocked_core_registers_[SP] = true;
833 blocked_core_registers_[LR] = true;
834 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100835
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100836 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100837 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100838
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100839 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100840 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100841
David Brazdil58282f42016-01-14 12:45:10 +0000842 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100843 // Stubs do not save callee-save floating point registers. If the graph
844 // is debuggable, we need to deal with these registers differently. For
845 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000846 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
847 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
848 }
849 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100850
851 UpdateBlockedPairRegisters();
852}
853
854void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
855 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
856 ArmManagedRegister current =
857 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
858 if (blocked_core_registers_[current.AsRegisterPairLow()]
859 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
860 blocked_register_pairs_[i] = true;
861 }
862 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100863}
864
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100865InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -0800866 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100867 assembler_(codegen->GetAssembler()),
868 codegen_(codegen) {}
869
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000870void CodeGeneratorARM::ComputeSpillMask() {
871 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
872 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +0000873 // There is no easy instruction to restore just the PC on thumb2. We spill and
874 // restore another arbitrary register.
875 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000876 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
877 // We use vpush and vpop for saving and restoring floating point registers, which take
878 // a SRegister and the number of registers to save/restore after that SRegister. We
879 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
880 // but in the range.
881 if (fpu_spill_mask_ != 0) {
882 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
883 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
884 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
885 fpu_spill_mask_ |= (1 << i);
886 }
887 }
888}
889
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100890static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100891 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100892}
893
894static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100895 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100896}
897
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000898void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000899 bool skip_overflow_check =
900 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000901 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000902 __ Bind(&frame_entry_label_);
903
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000904 if (HasEmptyFrame()) {
905 return;
906 }
907
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100908 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000909 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
910 __ LoadFromOffset(kLoadWord, IP, IP, 0);
911 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100912 }
913
Andreas Gampe501fd632015-09-10 16:11:06 -0700914 __ PushList(core_spill_mask_);
915 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
916 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000917 if (fpu_spill_mask_ != 0) {
918 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
919 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100920 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100921 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000922 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100923 int adjust = GetFrameSize() - FrameEntrySpillSize();
924 __ AddConstant(SP, -adjust);
925 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100926 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000927}
928
929void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000930 if (HasEmptyFrame()) {
931 __ bx(LR);
932 return;
933 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100934 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100935 int adjust = GetFrameSize() - FrameEntrySpillSize();
936 __ AddConstant(SP, adjust);
937 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000938 if (fpu_spill_mask_ != 0) {
939 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
940 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100941 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
942 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000943 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700944 // Pop LR into PC to return.
945 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
946 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
947 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100948 __ cfi().RestoreState();
949 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000950}
951
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100952void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700953 Label* label = GetLabelOf(block);
954 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000955}
956
David Brazdil60328912016-04-04 17:47:42 +0000957Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
958 switch (load->GetType()) {
959 case Primitive::kPrimLong:
960 case Primitive::kPrimDouble:
961 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
962
963 case Primitive::kPrimInt:
964 case Primitive::kPrimNot:
965 case Primitive::kPrimFloat:
966 return Location::StackSlot(GetStackSlot(load->GetLocal()));
967
968 case Primitive::kPrimBoolean:
969 case Primitive::kPrimByte:
970 case Primitive::kPrimChar:
971 case Primitive::kPrimShort:
972 case Primitive::kPrimVoid:
973 LOG(FATAL) << "Unexpected type " << load->GetType();
974 UNREACHABLE();
975 }
976
977 LOG(FATAL) << "Unreachable";
978 UNREACHABLE();
979}
980
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100981Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100982 switch (type) {
983 case Primitive::kPrimBoolean:
984 case Primitive::kPrimByte:
985 case Primitive::kPrimChar:
986 case Primitive::kPrimShort:
987 case Primitive::kPrimInt:
988 case Primitive::kPrimNot: {
989 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000990 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100991 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100992 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100993 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000994 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100995 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100996 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100997
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000998 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100999 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001000 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001001 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001002 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001003 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001004 if (calling_convention.GetRegisterAt(index) == R1) {
1005 // Skip R1, and use R2_R3 instead.
1006 gp_index_++;
1007 index++;
1008 }
1009 }
1010 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
1011 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001012 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01001013
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00001014 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00001015 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001016 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001017 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
1018 }
1019 }
1020
1021 case Primitive::kPrimFloat: {
1022 uint32_t stack_index = stack_index_++;
1023 if (float_index_ % 2 == 0) {
1024 float_index_ = std::max(double_index_, float_index_);
1025 }
1026 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
1027 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
1028 } else {
1029 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
1030 }
1031 }
1032
1033 case Primitive::kPrimDouble: {
1034 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
1035 uint32_t stack_index = stack_index_;
1036 stack_index_ += 2;
1037 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
1038 uint32_t index = double_index_;
1039 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001040 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001041 calling_convention.GetFpuRegisterAt(index),
1042 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001043 DCHECK(ExpectedPairLayout(result));
1044 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001045 } else {
1046 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001047 }
1048 }
1049
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001050 case Primitive::kPrimVoid:
1051 LOG(FATAL) << "Unexpected parameter type " << type;
1052 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001053 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001054 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001055}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001056
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001057Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001058 switch (type) {
1059 case Primitive::kPrimBoolean:
1060 case Primitive::kPrimByte:
1061 case Primitive::kPrimChar:
1062 case Primitive::kPrimShort:
1063 case Primitive::kPrimInt:
1064 case Primitive::kPrimNot: {
1065 return Location::RegisterLocation(R0);
1066 }
1067
1068 case Primitive::kPrimFloat: {
1069 return Location::FpuRegisterLocation(S0);
1070 }
1071
1072 case Primitive::kPrimLong: {
1073 return Location::RegisterPairLocation(R0, R1);
1074 }
1075
1076 case Primitive::kPrimDouble: {
1077 return Location::FpuRegisterPairLocation(S0, S1);
1078 }
1079
1080 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00001081 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001082 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01001083
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001084 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001085}
1086
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001087Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
1088 return Location::RegisterLocation(kMethodRegisterArgument);
1089}
1090
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001091void CodeGeneratorARM::Move32(Location destination, Location source) {
1092 if (source.Equals(destination)) {
1093 return;
1094 }
1095 if (destination.IsRegister()) {
1096 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001097 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001099 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001100 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001101 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001102 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 } else if (destination.IsFpuRegister()) {
1104 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001105 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001106 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001107 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001108 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001110 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001111 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001112 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001113 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001114 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001115 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001116 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001117 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00001118 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001119 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
1120 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001121 }
1122 }
1123}
1124
1125void CodeGeneratorARM::Move64(Location destination, Location source) {
1126 if (source.Equals(destination)) {
1127 return;
1128 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001129 if (destination.IsRegisterPair()) {
1130 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001131 EmitParallelMoves(
1132 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
1133 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001134 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001135 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001136 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
1137 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001138 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001139 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001140 } else if (source.IsFpuRegisterPair()) {
1141 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
1142 destination.AsRegisterPairHigh<Register>(),
1143 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001144 } else {
1145 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001146 DCHECK(ExpectedPairLayout(destination));
1147 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
1148 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001149 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001150 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001151 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001152 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1153 SP,
1154 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01001155 } else if (source.IsRegisterPair()) {
1156 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
1157 source.AsRegisterPairLow<Register>(),
1158 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001159 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001160 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001161 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001162 } else {
1163 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001164 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001165 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001166 if (source.AsRegisterPairLow<Register>() == R1) {
1167 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001168 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
1169 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001170 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001171 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001172 SP, destination.GetStackIndex());
1173 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001174 } else if (source.IsFpuRegisterPair()) {
1175 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
1176 SP,
1177 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001178 } else {
1179 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001180 EmitParallelMoves(
1181 Location::StackSlot(source.GetStackIndex()),
1182 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001183 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00001184 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01001185 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
1186 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001187 }
1188 }
1189}
1190
Calin Juravle175dc732015-08-25 15:42:32 +01001191void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1192 DCHECK(location.IsRegister());
1193 __ LoadImmediate(location.AsRegister<Register>(), value);
1194}
1195
Calin Juravlee460d1d2015-09-29 04:52:17 +01001196void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00001197 HParallelMove move(GetGraph()->GetArena());
1198 move.AddMove(src, dst, dst_type, nullptr);
1199 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01001200}
1201
1202void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1203 if (location.IsRegister()) {
1204 locations->AddTemp(location);
1205 } else if (location.IsRegisterPair()) {
1206 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1207 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1208 } else {
1209 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1210 }
1211}
1212
Calin Juravle175dc732015-08-25 15:42:32 +01001213void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1214 HInstruction* instruction,
1215 uint32_t dex_pc,
1216 SlowPathCode* slow_path) {
1217 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1218 instruction,
1219 dex_pc,
1220 slow_path);
1221}
1222
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001223void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1224 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001225 uint32_t dex_pc,
1226 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001227 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001228 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1229 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001230 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001231}
1232
David Brazdilfc6a86a2015-06-26 10:33:45 +00001233void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001234 DCHECK(!successor->IsExitBlock());
1235
1236 HBasicBlock* block = got->GetBlock();
1237 HInstruction* previous = got->GetPrevious();
1238
1239 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001240 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001241 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1242 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1243 return;
1244 }
1245
1246 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1247 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1248 }
1249 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001250 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001251 }
1252}
1253
David Brazdilfc6a86a2015-06-26 10:33:45 +00001254void LocationsBuilderARM::VisitGoto(HGoto* got) {
1255 got->SetLocations(nullptr);
1256}
1257
1258void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1259 HandleGoto(got, got->GetSuccessor());
1260}
1261
1262void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1263 try_boundary->SetLocations(nullptr);
1264}
1265
1266void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1267 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1268 if (!successor->IsExitBlock()) {
1269 HandleGoto(try_boundary, successor);
1270 }
1271}
1272
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001273void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001274 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001275}
1276
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001277void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001278}
1279
Roland Levillain4fa13f62015-07-06 18:11:54 +01001280void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1281 Label* true_label,
Vladimir Markod6e069b2016-01-18 11:11:01 +00001282 Label* false_label ATTRIBUTE_UNUSED) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001283 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00001284 __ b(true_label, ARMFPCondition(cond->GetCondition(), cond->IsGtBias()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001285}
1286
1287void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1288 Label* true_label,
1289 Label* false_label) {
1290 LocationSummary* locations = cond->GetLocations();
1291 Location left = locations->InAt(0);
1292 Location right = locations->InAt(1);
1293 IfCondition if_cond = cond->GetCondition();
1294
1295 Register left_high = left.AsRegisterPairHigh<Register>();
1296 Register left_low = left.AsRegisterPairLow<Register>();
1297 IfCondition true_high_cond = if_cond;
1298 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001299 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001300
1301 // Set the conditions for the test, remembering that == needs to be
1302 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001303 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001304 switch (if_cond) {
1305 case kCondEQ:
1306 case kCondNE:
1307 // Nothing to do.
1308 break;
1309 case kCondLT:
1310 false_high_cond = kCondGT;
1311 break;
1312 case kCondLE:
1313 true_high_cond = kCondLT;
1314 break;
1315 case kCondGT:
1316 false_high_cond = kCondLT;
1317 break;
1318 case kCondGE:
1319 true_high_cond = kCondGT;
1320 break;
Aart Bike9f37602015-10-09 11:15:55 -07001321 case kCondB:
1322 false_high_cond = kCondA;
1323 break;
1324 case kCondBE:
1325 true_high_cond = kCondB;
1326 break;
1327 case kCondA:
1328 false_high_cond = kCondB;
1329 break;
1330 case kCondAE:
1331 true_high_cond = kCondA;
1332 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001333 }
1334 if (right.IsConstant()) {
1335 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1336 int32_t val_low = Low32Bits(value);
1337 int32_t val_high = High32Bits(value);
1338
Vladimir Markoac6ac102015-12-17 12:14:00 +00001339 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001340 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001341 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001342 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001343 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001344 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001345 __ b(true_label, ARMCondition(true_high_cond));
1346 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001347 }
1348 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00001349 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001350 } else {
1351 Register right_high = right.AsRegisterPairHigh<Register>();
1352 Register right_low = right.AsRegisterPairLow<Register>();
1353
1354 __ cmp(left_high, ShifterOperand(right_high));
1355 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001356 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001357 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001358 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001359 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001360 __ b(true_label, ARMCondition(true_high_cond));
1361 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001362 }
1363 // Must be equal high, so compare the lows.
1364 __ cmp(left_low, ShifterOperand(right_low));
1365 }
1366 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001367 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001368 __ b(true_label, final_condition);
1369}
1370
David Brazdil0debae72015-11-12 18:37:00 +00001371void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1372 Label* true_target_in,
1373 Label* false_target_in) {
1374 // Generated branching requires both targets to be explicit. If either of the
1375 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1376 Label fallthrough_target;
1377 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1378 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1379
Roland Levillain4fa13f62015-07-06 18:11:54 +01001380 LocationSummary* locations = condition->GetLocations();
1381 Location left = locations->InAt(0);
1382 Location right = locations->InAt(1);
1383
Roland Levillain4fa13f62015-07-06 18:11:54 +01001384 Primitive::Type type = condition->InputAt(0)->GetType();
1385 switch (type) {
1386 case Primitive::kPrimLong:
1387 GenerateLongComparesAndJumps(condition, true_target, false_target);
1388 break;
1389 case Primitive::kPrimFloat:
1390 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1391 GenerateFPJumps(condition, true_target, false_target);
1392 break;
1393 case Primitive::kPrimDouble:
1394 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1395 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1396 GenerateFPJumps(condition, true_target, false_target);
1397 break;
1398 default:
1399 LOG(FATAL) << "Unexpected compare type " << type;
1400 }
1401
David Brazdil0debae72015-11-12 18:37:00 +00001402 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001403 __ b(false_target);
1404 }
David Brazdil0debae72015-11-12 18:37:00 +00001405
1406 if (fallthrough_target.IsLinked()) {
1407 __ Bind(&fallthrough_target);
1408 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001409}
1410
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001411void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001412 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001413 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001414 Label* false_target) {
1415 HInstruction* cond = instruction->InputAt(condition_input_index);
1416
1417 if (true_target == nullptr && false_target == nullptr) {
1418 // Nothing to do. The code always falls through.
1419 return;
1420 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00001421 // Constant condition, statically compared against "true" (integer value 1).
1422 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00001423 if (true_target != nullptr) {
1424 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001425 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001426 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00001427 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00001428 if (false_target != nullptr) {
1429 __ b(false_target);
1430 }
1431 }
1432 return;
1433 }
1434
1435 // The following code generates these patterns:
1436 // (1) true_target == nullptr && false_target != nullptr
1437 // - opposite condition true => branch to false_target
1438 // (2) true_target != nullptr && false_target == nullptr
1439 // - condition true => branch to true_target
1440 // (3) true_target != nullptr && false_target != nullptr
1441 // - condition true => branch to true_target
1442 // - branch to false_target
1443 if (IsBooleanValueOrMaterializedCondition(cond)) {
1444 // Condition has been materialized, compare the output to 0.
1445 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1446 DCHECK(cond_val.IsRegister());
1447 if (true_target == nullptr) {
1448 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1449 } else {
1450 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001451 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001452 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001453 // Condition has not been materialized. Use its inputs as the comparison and
1454 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001455 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001456
1457 // If this is a long or FP comparison that has been folded into
1458 // the HCondition, generate the comparison directly.
1459 Primitive::Type type = condition->InputAt(0)->GetType();
1460 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1461 GenerateCompareTestAndBranch(condition, true_target, false_target);
1462 return;
1463 }
1464
1465 LocationSummary* locations = cond->GetLocations();
1466 DCHECK(locations->InAt(0).IsRegister());
1467 Register left = locations->InAt(0).AsRegister<Register>();
1468 Location right = locations->InAt(1);
1469 if (right.IsRegister()) {
1470 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001471 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001472 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001473 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
David Brazdil0debae72015-11-12 18:37:00 +00001474 }
1475 if (true_target == nullptr) {
1476 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1477 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001478 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001479 }
Dave Allison20dfc792014-06-16 20:44:29 -07001480 }
David Brazdil0debae72015-11-12 18:37:00 +00001481
1482 // If neither branch falls through (case 3), the conditional branch to `true_target`
1483 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1484 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001485 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001486 }
1487}
1488
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001489void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001490 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1491 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001492 locations->SetInAt(0, Location::RequiresRegister());
1493 }
1494}
1495
1496void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001497 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1498 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1499 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1500 nullptr : codegen_->GetLabelOf(true_successor);
1501 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1502 nullptr : codegen_->GetLabelOf(false_successor);
1503 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001504}
1505
1506void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1507 LocationSummary* locations = new (GetGraph()->GetArena())
1508 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001509 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001510 locations->SetInAt(0, Location::RequiresRegister());
1511 }
1512}
1513
1514void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08001515 SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00001516 GenerateTestAndBranch(deoptimize,
1517 /* condition_input_index */ 0,
1518 slow_path->GetEntryLabel(),
1519 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001520}
Dave Allison20dfc792014-06-16 20:44:29 -07001521
David Brazdil74eb1b22015-12-14 11:44:01 +00001522void LocationsBuilderARM::VisitSelect(HSelect* select) {
1523 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
1524 if (Primitive::IsFloatingPointType(select->GetType())) {
1525 locations->SetInAt(0, Location::RequiresFpuRegister());
1526 locations->SetInAt(1, Location::RequiresFpuRegister());
1527 } else {
1528 locations->SetInAt(0, Location::RequiresRegister());
1529 locations->SetInAt(1, Location::RequiresRegister());
1530 }
1531 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
1532 locations->SetInAt(2, Location::RequiresRegister());
1533 }
1534 locations->SetOut(Location::SameAsFirstInput());
1535}
1536
1537void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
1538 LocationSummary* locations = select->GetLocations();
1539 Label false_target;
1540 GenerateTestAndBranch(select,
1541 /* condition_input_index */ 2,
1542 /* true_target */ nullptr,
1543 &false_target);
1544 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
1545 __ Bind(&false_target);
1546}
1547
David Srbecky0cf44932015-12-09 14:09:59 +00001548void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
1549 new (GetGraph()->GetArena()) LocationSummary(info);
1550}
1551
David Srbeckyd28f4a02016-03-14 17:14:24 +00001552void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
1553 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00001554}
1555
1556void CodeGeneratorARM::GenerateNop() {
1557 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00001558}
1559
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001560void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001561 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001562 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001563 // Handle the long/FP comparisons made in instruction simplification.
1564 switch (cond->InputAt(0)->GetType()) {
1565 case Primitive::kPrimLong:
1566 locations->SetInAt(0, Location::RequiresRegister());
1567 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001568 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001569 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1570 }
1571 break;
1572
1573 case Primitive::kPrimFloat:
1574 case Primitive::kPrimDouble:
1575 locations->SetInAt(0, Location::RequiresFpuRegister());
1576 locations->SetInAt(1, Location::RequiresFpuRegister());
David Brazdilb3e773e2016-01-26 11:28:37 +00001577 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001578 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1579 }
1580 break;
1581
1582 default:
1583 locations->SetInAt(0, Location::RequiresRegister());
1584 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00001585 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001586 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1587 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001588 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001589}
1590
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001591void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00001592 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001593 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001594 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001595
1596 LocationSummary* locations = cond->GetLocations();
1597 Location left = locations->InAt(0);
1598 Location right = locations->InAt(1);
1599 Register out = locations->Out().AsRegister<Register>();
1600 Label true_label, false_label;
1601
1602 switch (cond->InputAt(0)->GetType()) {
1603 default: {
1604 // Integer case.
1605 if (right.IsRegister()) {
1606 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1607 } else {
1608 DCHECK(right.IsConstant());
Vladimir Markoac6ac102015-12-17 12:14:00 +00001609 __ CmpConstant(left.AsRegister<Register>(),
1610 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001611 }
Aart Bike9f37602015-10-09 11:15:55 -07001612 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001613 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001614 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001615 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001616 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001617 return;
1618 }
1619 case Primitive::kPrimLong:
1620 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1621 break;
1622 case Primitive::kPrimFloat:
1623 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1624 GenerateFPJumps(cond, &true_label, &false_label);
1625 break;
1626 case Primitive::kPrimDouble:
1627 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1628 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1629 GenerateFPJumps(cond, &true_label, &false_label);
1630 break;
1631 }
1632
1633 // Convert the jumps into the result.
1634 Label done_label;
1635
1636 // False case: result = 0.
1637 __ Bind(&false_label);
1638 __ LoadImmediate(out, 0);
1639 __ b(&done_label);
1640
1641 // True case: result = 1.
1642 __ Bind(&true_label);
1643 __ LoadImmediate(out, 1);
1644 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001645}
1646
1647void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001648 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001649}
1650
1651void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001652 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001653}
1654
1655void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001656 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001657}
1658
1659void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001660 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001661}
1662
1663void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001664 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001665}
1666
1667void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001668 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001669}
1670
1671void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001672 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001673}
1674
1675void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001676 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001677}
1678
1679void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001680 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001681}
1682
1683void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001684 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001685}
1686
1687void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001688 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07001689}
1690
1691void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001692 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001693}
1694
Aart Bike9f37602015-10-09 11:15:55 -07001695void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001696 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001697}
1698
1699void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001700 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001701}
1702
1703void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001704 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001705}
1706
1707void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001708 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001709}
1710
1711void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001712 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001713}
1714
1715void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001716 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001717}
1718
1719void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001720 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001721}
1722
1723void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00001724 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07001725}
1726
David Brazdil60328912016-04-04 17:47:42 +00001727void LocationsBuilderARM::VisitLocal(HLocal* local) {
1728 local->SetLocations(nullptr);
1729}
1730
1731void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1732 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1733}
1734
1735void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
1736 load->SetLocations(nullptr);
1737}
1738
1739void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
1740 // Nothing to do, this is driven by the code generator.
1741}
1742
1743void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
1744 LocationSummary* locations =
1745 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
1746 switch (store->InputAt(1)->GetType()) {
1747 case Primitive::kPrimBoolean:
1748 case Primitive::kPrimByte:
1749 case Primitive::kPrimChar:
1750 case Primitive::kPrimShort:
1751 case Primitive::kPrimInt:
1752 case Primitive::kPrimNot:
1753 case Primitive::kPrimFloat:
1754 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1755 break;
1756
1757 case Primitive::kPrimLong:
1758 case Primitive::kPrimDouble:
1759 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1760 break;
1761
1762 default:
1763 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
1764 }
1765}
1766
1767void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
1768}
1769
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001770void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001771 LocationSummary* locations =
1772 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001773 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001774}
1775
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001776void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001777 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001778}
1779
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001780void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1781 LocationSummary* locations =
1782 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1783 locations->SetOut(Location::ConstantLocation(constant));
1784}
1785
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001786void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001787 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001788}
1789
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001790void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001791 LocationSummary* locations =
1792 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001793 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001794}
1795
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001796void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001797 // Will be generated at use site.
1798}
1799
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001800void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1801 LocationSummary* locations =
1802 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1803 locations->SetOut(Location::ConstantLocation(constant));
1804}
1805
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001806void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001807 // Will be generated at use site.
1808}
1809
1810void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1811 LocationSummary* locations =
1812 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1813 locations->SetOut(Location::ConstantLocation(constant));
1814}
1815
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001816void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001817 // Will be generated at use site.
1818}
1819
Calin Juravle27df7582015-04-17 19:12:31 +01001820void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1821 memory_barrier->SetLocations(nullptr);
1822}
1823
1824void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00001825 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01001826}
1827
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001828void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001829 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001830}
1831
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001832void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001833 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001834}
1835
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001836void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001837 LocationSummary* locations =
1838 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001839 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001840}
1841
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001842void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001843 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001844}
1845
Calin Juravle175dc732015-08-25 15:42:32 +01001846void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1847 // The trampoline uses the same calling convention as dex calling conventions,
1848 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1849 // the method_idx.
1850 HandleInvoke(invoke);
1851}
1852
1853void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1854 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1855}
1856
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001857void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001858 // Explicit clinit checks triggered by static invokes must have been pruned by
1859 // art::PrepareForRegisterAllocation.
1860 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001861
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001862 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001863 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001864 codegen_->GetInstructionSetFeatures());
1865 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00001866 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
1867 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
1868 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001869 return;
1870 }
1871
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001872 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00001873
1874 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
1875 if (invoke->HasPcRelativeDexCache()) {
1876 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
1877 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001878}
1879
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001880static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1881 if (invoke->GetLocations()->Intrinsified()) {
1882 IntrinsicCodeGeneratorARM intrinsic(codegen);
1883 intrinsic.Dispatch(invoke);
1884 return true;
1885 }
1886 return false;
1887}
1888
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001889void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00001890 // Explicit clinit checks triggered by static invokes must have been pruned by
1891 // art::PrepareForRegisterAllocation.
1892 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001893
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001894 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1895 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001896 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001897
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001898 LocationSummary* locations = invoke->GetLocations();
1899 codegen_->GenerateStaticOrDirectCall(
1900 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001901 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001902}
1903
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001904void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001905 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001906 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001907}
1908
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001909void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001910 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001911 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001912 codegen_->GetInstructionSetFeatures());
1913 if (intrinsic.TryDispatch(invoke)) {
1914 return;
1915 }
1916
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001917 HandleInvoke(invoke);
1918}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001919
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001920void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001921 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1922 return;
1923 }
1924
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001925 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001926 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001927 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001928}
1929
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001930void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1931 HandleInvoke(invoke);
1932 // Add the hidden argument.
1933 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1934}
1935
1936void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1937 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00001938 LocationSummary* locations = invoke->GetLocations();
1939 Register temp = locations->GetTemp(0).AsRegister<Register>();
1940 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001941 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1942 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001943 Location receiver = locations->InAt(0);
1944 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1945
Roland Levillain3b359c72015-11-17 19:35:12 +00001946 // Set the hidden argument. This is safe to do this here, as R12
1947 // won't be modified thereafter, before the `blx` (call) instruction.
1948 DCHECK_EQ(R12, hidden_reg);
1949 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001950
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001951 if (receiver.IsStackSlot()) {
1952 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00001953 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001954 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1955 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00001956 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00001957 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001958 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001959 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00001960 // Instead of simply (possibly) unpoisoning `temp` here, we should
1961 // emit a read barrier for the previous class reference load.
1962 // However this is not required in practice, as this is an
1963 // intermediate/temporary reference and because the current
1964 // concurrent copying collector keeps the from-space memory
1965 // intact/accessible until the end of the marking phase (the
1966 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01001967 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001968 // temp = temp->GetImtEntryAt(method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001969 uint32_t entry_point =
1970 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001971 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1972 // LR = temp->GetEntryPoint();
1973 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1974 // LR();
1975 __ blx(LR);
1976 DCHECK(!codegen_->IsLeafMethod());
1977 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1978}
1979
Roland Levillain88cb1752014-10-20 16:36:47 +01001980void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1981 LocationSummary* locations =
1982 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1983 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001984 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001985 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001986 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1987 break;
1988 }
1989 case Primitive::kPrimLong: {
1990 locations->SetInAt(0, Location::RequiresRegister());
1991 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001992 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001993 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001994
Roland Levillain88cb1752014-10-20 16:36:47 +01001995 case Primitive::kPrimFloat:
1996 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001997 locations->SetInAt(0, Location::RequiresFpuRegister());
1998 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001999 break;
2000
2001 default:
2002 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2003 }
2004}
2005
2006void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
2007 LocationSummary* locations = neg->GetLocations();
2008 Location out = locations->Out();
2009 Location in = locations->InAt(0);
2010 switch (neg->GetResultType()) {
2011 case Primitive::kPrimInt:
2012 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002013 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01002014 break;
2015
2016 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01002017 DCHECK(in.IsRegisterPair());
2018 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
2019 __ rsbs(out.AsRegisterPairLow<Register>(),
2020 in.AsRegisterPairLow<Register>(),
2021 ShifterOperand(0));
2022 // We cannot emit an RSC (Reverse Subtract with Carry)
2023 // instruction here, as it does not exist in the Thumb-2
2024 // instruction set. We use the following approach
2025 // using SBC and SUB instead.
2026 //
2027 // out.hi = -C
2028 __ sbc(out.AsRegisterPairHigh<Register>(),
2029 out.AsRegisterPairHigh<Register>(),
2030 ShifterOperand(out.AsRegisterPairHigh<Register>()));
2031 // out.hi = out.hi - in.hi
2032 __ sub(out.AsRegisterPairHigh<Register>(),
2033 out.AsRegisterPairHigh<Register>(),
2034 ShifterOperand(in.AsRegisterPairHigh<Register>()));
2035 break;
2036
Roland Levillain88cb1752014-10-20 16:36:47 +01002037 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002038 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002039 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00002040 break;
2041
Roland Levillain88cb1752014-10-20 16:36:47 +01002042 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00002043 DCHECK(in.IsFpuRegisterPair());
2044 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2045 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01002046 break;
2047
2048 default:
2049 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2050 }
2051}
2052
Roland Levillaindff1f282014-11-05 14:15:05 +00002053void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00002054 Primitive::Type result_type = conversion->GetResultType();
2055 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002056 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00002057
Roland Levillain5b3ee562015-04-14 16:02:41 +01002058 // The float-to-long, double-to-long and long-to-float type conversions
2059 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00002060 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01002061 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
2062 && result_type == Primitive::kPrimLong)
2063 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00002064 ? LocationSummary::kCall
2065 : LocationSummary::kNoCall;
2066 LocationSummary* locations =
2067 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
2068
David Brazdilb2bd1c52015-03-25 11:17:37 +00002069 // The Java language does not allow treating boolean as an integral type but
2070 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00002071
Roland Levillaindff1f282014-11-05 14:15:05 +00002072 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002073 case Primitive::kPrimByte:
2074 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002075 case Primitive::kPrimLong:
2076 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002077 case Primitive::kPrimBoolean:
2078 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002079 case Primitive::kPrimShort:
2080 case Primitive::kPrimInt:
2081 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002082 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002083 locations->SetInAt(0, Location::RequiresRegister());
2084 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2085 break;
2086
2087 default:
2088 LOG(FATAL) << "Unexpected type conversion from " << input_type
2089 << " to " << result_type;
2090 }
2091 break;
2092
Roland Levillain01a8d712014-11-14 16:27:39 +00002093 case Primitive::kPrimShort:
2094 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002095 case Primitive::kPrimLong:
2096 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002097 case Primitive::kPrimBoolean:
2098 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002099 case Primitive::kPrimByte:
2100 case Primitive::kPrimInt:
2101 case Primitive::kPrimChar:
2102 // Processing a Dex `int-to-short' instruction.
2103 locations->SetInAt(0, Location::RequiresRegister());
2104 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2105 break;
2106
2107 default:
2108 LOG(FATAL) << "Unexpected type conversion from " << input_type
2109 << " to " << result_type;
2110 }
2111 break;
2112
Roland Levillain946e1432014-11-11 17:35:19 +00002113 case Primitive::kPrimInt:
2114 switch (input_type) {
2115 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002116 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002117 locations->SetInAt(0, Location::Any());
2118 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2119 break;
2120
2121 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00002122 // Processing a Dex `float-to-int' instruction.
2123 locations->SetInAt(0, Location::RequiresFpuRegister());
2124 locations->SetOut(Location::RequiresRegister());
2125 locations->AddTemp(Location::RequiresFpuRegister());
2126 break;
2127
Roland Levillain946e1432014-11-11 17:35:19 +00002128 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002129 // Processing a Dex `double-to-int' instruction.
2130 locations->SetInAt(0, Location::RequiresFpuRegister());
2131 locations->SetOut(Location::RequiresRegister());
2132 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00002133 break;
2134
2135 default:
2136 LOG(FATAL) << "Unexpected type conversion from " << input_type
2137 << " to " << result_type;
2138 }
2139 break;
2140
Roland Levillaindff1f282014-11-05 14:15:05 +00002141 case Primitive::kPrimLong:
2142 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002143 case Primitive::kPrimBoolean:
2144 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002145 case Primitive::kPrimByte:
2146 case Primitive::kPrimShort:
2147 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002148 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002149 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002150 locations->SetInAt(0, Location::RequiresRegister());
2151 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2152 break;
2153
Roland Levillain624279f2014-12-04 11:54:28 +00002154 case Primitive::kPrimFloat: {
2155 // Processing a Dex `float-to-long' instruction.
2156 InvokeRuntimeCallingConvention calling_convention;
2157 locations->SetInAt(0, Location::FpuRegisterLocation(
2158 calling_convention.GetFpuRegisterAt(0)));
2159 locations->SetOut(Location::RegisterPairLocation(R0, R1));
2160 break;
2161 }
2162
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002163 case Primitive::kPrimDouble: {
2164 // Processing a Dex `double-to-long' instruction.
2165 InvokeRuntimeCallingConvention calling_convention;
2166 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2167 calling_convention.GetFpuRegisterAt(0),
2168 calling_convention.GetFpuRegisterAt(1)));
2169 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00002170 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002171 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002172
2173 default:
2174 LOG(FATAL) << "Unexpected type conversion from " << input_type
2175 << " to " << result_type;
2176 }
2177 break;
2178
Roland Levillain981e4542014-11-14 11:47:14 +00002179 case Primitive::kPrimChar:
2180 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002181 case Primitive::kPrimLong:
2182 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00002183 case Primitive::kPrimBoolean:
2184 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002185 case Primitive::kPrimByte:
2186 case Primitive::kPrimShort:
2187 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002188 // Processing a Dex `int-to-char' instruction.
2189 locations->SetInAt(0, Location::RequiresRegister());
2190 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2191 break;
2192
2193 default:
2194 LOG(FATAL) << "Unexpected type conversion from " << input_type
2195 << " to " << result_type;
2196 }
2197 break;
2198
Roland Levillaindff1f282014-11-05 14:15:05 +00002199 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002200 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002201 case Primitive::kPrimBoolean:
2202 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002203 case Primitive::kPrimByte:
2204 case Primitive::kPrimShort:
2205 case Primitive::kPrimInt:
2206 case Primitive::kPrimChar:
2207 // Processing a Dex `int-to-float' instruction.
2208 locations->SetInAt(0, Location::RequiresRegister());
2209 locations->SetOut(Location::RequiresFpuRegister());
2210 break;
2211
Roland Levillain5b3ee562015-04-14 16:02:41 +01002212 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002213 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002214 InvokeRuntimeCallingConvention calling_convention;
2215 locations->SetInAt(0, Location::RegisterPairLocation(
2216 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2217 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002218 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002219 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002220
Roland Levillaincff13742014-11-17 14:32:17 +00002221 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002222 // Processing a Dex `double-to-float' instruction.
2223 locations->SetInAt(0, Location::RequiresFpuRegister());
2224 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002225 break;
2226
2227 default:
2228 LOG(FATAL) << "Unexpected type conversion from " << input_type
2229 << " to " << result_type;
2230 };
2231 break;
2232
Roland Levillaindff1f282014-11-05 14:15:05 +00002233 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002234 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002235 case Primitive::kPrimBoolean:
2236 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002237 case Primitive::kPrimByte:
2238 case Primitive::kPrimShort:
2239 case Primitive::kPrimInt:
2240 case Primitive::kPrimChar:
2241 // Processing a Dex `int-to-double' instruction.
2242 locations->SetInAt(0, Location::RequiresRegister());
2243 locations->SetOut(Location::RequiresFpuRegister());
2244 break;
2245
2246 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002247 // Processing a Dex `long-to-double' instruction.
2248 locations->SetInAt(0, Location::RequiresRegister());
2249 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002250 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002251 locations->AddTemp(Location::RequiresFpuRegister());
2252 break;
2253
Roland Levillaincff13742014-11-17 14:32:17 +00002254 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002255 // Processing a Dex `float-to-double' instruction.
2256 locations->SetInAt(0, Location::RequiresFpuRegister());
2257 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002258 break;
2259
2260 default:
2261 LOG(FATAL) << "Unexpected type conversion from " << input_type
2262 << " to " << result_type;
2263 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002264 break;
2265
2266 default:
2267 LOG(FATAL) << "Unexpected type conversion from " << input_type
2268 << " to " << result_type;
2269 }
2270}
2271
2272void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2273 LocationSummary* locations = conversion->GetLocations();
2274 Location out = locations->Out();
2275 Location in = locations->InAt(0);
2276 Primitive::Type result_type = conversion->GetResultType();
2277 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002278 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002279 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002280 case Primitive::kPrimByte:
2281 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002282 case Primitive::kPrimLong:
2283 // Type conversion from long to byte is a result of code transformations.
2284 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
2285 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002286 case Primitive::kPrimBoolean:
2287 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002288 case Primitive::kPrimShort:
2289 case Primitive::kPrimInt:
2290 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002291 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002292 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002293 break;
2294
2295 default:
2296 LOG(FATAL) << "Unexpected type conversion from " << input_type
2297 << " to " << result_type;
2298 }
2299 break;
2300
Roland Levillain01a8d712014-11-14 16:27:39 +00002301 case Primitive::kPrimShort:
2302 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002303 case Primitive::kPrimLong:
2304 // Type conversion from long to short is a result of code transformations.
2305 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2306 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002307 case Primitive::kPrimBoolean:
2308 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002309 case Primitive::kPrimByte:
2310 case Primitive::kPrimInt:
2311 case Primitive::kPrimChar:
2312 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002313 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002314 break;
2315
2316 default:
2317 LOG(FATAL) << "Unexpected type conversion from " << input_type
2318 << " to " << result_type;
2319 }
2320 break;
2321
Roland Levillain946e1432014-11-11 17:35:19 +00002322 case Primitive::kPrimInt:
2323 switch (input_type) {
2324 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002325 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002326 DCHECK(out.IsRegister());
2327 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002328 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002329 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002330 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002331 } else {
2332 DCHECK(in.IsConstant());
2333 DCHECK(in.GetConstant()->IsLongConstant());
2334 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002335 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002336 }
2337 break;
2338
Roland Levillain3f8f9362014-12-02 17:45:01 +00002339 case Primitive::kPrimFloat: {
2340 // Processing a Dex `float-to-int' instruction.
2341 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2342 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2343 __ vcvtis(temp, temp);
2344 __ vmovrs(out.AsRegister<Register>(), temp);
2345 break;
2346 }
2347
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002348 case Primitive::kPrimDouble: {
2349 // Processing a Dex `double-to-int' instruction.
2350 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2351 DRegister temp_d = FromLowSToD(temp_s);
2352 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2353 __ vcvtid(temp_s, temp_d);
2354 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002355 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002356 }
Roland Levillain946e1432014-11-11 17:35:19 +00002357
2358 default:
2359 LOG(FATAL) << "Unexpected type conversion from " << input_type
2360 << " to " << result_type;
2361 }
2362 break;
2363
Roland Levillaindff1f282014-11-05 14:15:05 +00002364 case Primitive::kPrimLong:
2365 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002366 case Primitive::kPrimBoolean:
2367 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002368 case Primitive::kPrimByte:
2369 case Primitive::kPrimShort:
2370 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002371 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002372 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002373 DCHECK(out.IsRegisterPair());
2374 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002375 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002376 // Sign extension.
2377 __ Asr(out.AsRegisterPairHigh<Register>(),
2378 out.AsRegisterPairLow<Register>(),
2379 31);
2380 break;
2381
2382 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002383 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002384 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2385 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002386 conversion->GetDexPc(),
2387 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002388 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00002389 break;
2390
Roland Levillaindff1f282014-11-05 14:15:05 +00002391 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002392 // Processing a Dex `double-to-long' instruction.
2393 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2394 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002395 conversion->GetDexPc(),
2396 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002397 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00002398 break;
2399
2400 default:
2401 LOG(FATAL) << "Unexpected type conversion from " << input_type
2402 << " to " << result_type;
2403 }
2404 break;
2405
Roland Levillain981e4542014-11-14 11:47:14 +00002406 case Primitive::kPrimChar:
2407 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00002408 case Primitive::kPrimLong:
2409 // Type conversion from long to char is a result of code transformations.
2410 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
2411 break;
David Brazdil46e2a392015-03-16 17:31:52 +00002412 case Primitive::kPrimBoolean:
2413 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002414 case Primitive::kPrimByte:
2415 case Primitive::kPrimShort:
2416 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002417 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002418 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002419 break;
2420
2421 default:
2422 LOG(FATAL) << "Unexpected type conversion from " << input_type
2423 << " to " << result_type;
2424 }
2425 break;
2426
Roland Levillaindff1f282014-11-05 14:15:05 +00002427 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002428 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002429 case Primitive::kPrimBoolean:
2430 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002431 case Primitive::kPrimByte:
2432 case Primitive::kPrimShort:
2433 case Primitive::kPrimInt:
2434 case Primitive::kPrimChar: {
2435 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002436 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2437 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002438 break;
2439 }
2440
Roland Levillain5b3ee562015-04-14 16:02:41 +01002441 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002442 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002443 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2444 conversion,
2445 conversion->GetDexPc(),
2446 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002447 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00002448 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002449
Roland Levillaincff13742014-11-17 14:32:17 +00002450 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002451 // Processing a Dex `double-to-float' instruction.
2452 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2453 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002454 break;
2455
2456 default:
2457 LOG(FATAL) << "Unexpected type conversion from " << input_type
2458 << " to " << result_type;
2459 };
2460 break;
2461
Roland Levillaindff1f282014-11-05 14:15:05 +00002462 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002463 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002464 case Primitive::kPrimBoolean:
2465 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002466 case Primitive::kPrimByte:
2467 case Primitive::kPrimShort:
2468 case Primitive::kPrimInt:
2469 case Primitive::kPrimChar: {
2470 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002471 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002472 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2473 out.AsFpuRegisterPairLow<SRegister>());
2474 break;
2475 }
2476
Roland Levillain647b9ed2014-11-27 12:06:00 +00002477 case Primitive::kPrimLong: {
2478 // Processing a Dex `long-to-double' instruction.
2479 Register low = in.AsRegisterPairLow<Register>();
2480 Register high = in.AsRegisterPairHigh<Register>();
2481 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2482 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002483 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002484 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002485 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2486 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002487
Roland Levillain682393c2015-04-14 15:57:52 +01002488 // temp_d = int-to-double(high)
2489 __ vmovsr(temp_s, high);
2490 __ vcvtdi(temp_d, temp_s);
2491 // constant_d = k2Pow32EncodingForDouble
2492 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2493 // out_d = unsigned-to-double(low)
2494 __ vmovsr(out_s, low);
2495 __ vcvtdu(out_d, out_s);
2496 // out_d += temp_d * constant_d
2497 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002498 break;
2499 }
2500
Roland Levillaincff13742014-11-17 14:32:17 +00002501 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002502 // Processing a Dex `float-to-double' instruction.
2503 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2504 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002505 break;
2506
2507 default:
2508 LOG(FATAL) << "Unexpected type conversion from " << input_type
2509 << " to " << result_type;
2510 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002511 break;
2512
2513 default:
2514 LOG(FATAL) << "Unexpected type conversion from " << input_type
2515 << " to " << result_type;
2516 }
2517}
2518
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002519void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002520 LocationSummary* locations =
2521 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002522 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002523 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002524 locations->SetInAt(0, Location::RequiresRegister());
2525 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002526 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2527 break;
2528 }
2529
2530 case Primitive::kPrimLong: {
2531 locations->SetInAt(0, Location::RequiresRegister());
2532 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002533 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002534 break;
2535 }
2536
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002537 case Primitive::kPrimFloat:
2538 case Primitive::kPrimDouble: {
2539 locations->SetInAt(0, Location::RequiresFpuRegister());
2540 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002541 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002542 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002543 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002544
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002545 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002546 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002547 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002548}
2549
2550void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2551 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002552 Location out = locations->Out();
2553 Location first = locations->InAt(0);
2554 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002555 switch (add->GetResultType()) {
2556 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002557 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002558 __ add(out.AsRegister<Register>(),
2559 first.AsRegister<Register>(),
2560 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002561 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002562 __ AddConstant(out.AsRegister<Register>(),
2563 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002564 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002565 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002566 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002567
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002568 case Primitive::kPrimLong: {
2569 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002570 __ adds(out.AsRegisterPairLow<Register>(),
2571 first.AsRegisterPairLow<Register>(),
2572 ShifterOperand(second.AsRegisterPairLow<Register>()));
2573 __ adc(out.AsRegisterPairHigh<Register>(),
2574 first.AsRegisterPairHigh<Register>(),
2575 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002576 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002577 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002578
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002579 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002580 __ vadds(out.AsFpuRegister<SRegister>(),
2581 first.AsFpuRegister<SRegister>(),
2582 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002583 break;
2584
2585 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002586 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2587 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2588 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002589 break;
2590
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002591 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002592 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002593 }
2594}
2595
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002596void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002597 LocationSummary* locations =
2598 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002599 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002600 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002601 locations->SetInAt(0, Location::RequiresRegister());
2602 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002603 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2604 break;
2605 }
2606
2607 case Primitive::kPrimLong: {
2608 locations->SetInAt(0, Location::RequiresRegister());
2609 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002610 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002611 break;
2612 }
Calin Juravle11351682014-10-23 15:38:15 +01002613 case Primitive::kPrimFloat:
2614 case Primitive::kPrimDouble: {
2615 locations->SetInAt(0, Location::RequiresFpuRegister());
2616 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002617 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002618 break;
Calin Juravle11351682014-10-23 15:38:15 +01002619 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002620 default:
Calin Juravle11351682014-10-23 15:38:15 +01002621 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002622 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002623}
2624
2625void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2626 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002627 Location out = locations->Out();
2628 Location first = locations->InAt(0);
2629 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002630 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002631 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002632 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002633 __ sub(out.AsRegister<Register>(),
2634 first.AsRegister<Register>(),
2635 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002636 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002637 __ AddConstant(out.AsRegister<Register>(),
2638 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002639 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002640 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002641 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002642 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002643
Calin Juravle11351682014-10-23 15:38:15 +01002644 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002645 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002646 __ subs(out.AsRegisterPairLow<Register>(),
2647 first.AsRegisterPairLow<Register>(),
2648 ShifterOperand(second.AsRegisterPairLow<Register>()));
2649 __ sbc(out.AsRegisterPairHigh<Register>(),
2650 first.AsRegisterPairHigh<Register>(),
2651 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002652 break;
Calin Juravle11351682014-10-23 15:38:15 +01002653 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002654
Calin Juravle11351682014-10-23 15:38:15 +01002655 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002656 __ vsubs(out.AsFpuRegister<SRegister>(),
2657 first.AsFpuRegister<SRegister>(),
2658 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002659 break;
Calin Juravle11351682014-10-23 15:38:15 +01002660 }
2661
2662 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002663 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2664 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2665 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002666 break;
2667 }
2668
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002669
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002670 default:
Calin Juravle11351682014-10-23 15:38:15 +01002671 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002672 }
2673}
2674
Calin Juravle34bacdf2014-10-07 20:23:36 +01002675void LocationsBuilderARM::VisitMul(HMul* mul) {
2676 LocationSummary* locations =
2677 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2678 switch (mul->GetResultType()) {
2679 case Primitive::kPrimInt:
2680 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002681 locations->SetInAt(0, Location::RequiresRegister());
2682 locations->SetInAt(1, Location::RequiresRegister());
2683 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002684 break;
2685 }
2686
Calin Juravleb5bfa962014-10-21 18:02:24 +01002687 case Primitive::kPrimFloat:
2688 case Primitive::kPrimDouble: {
2689 locations->SetInAt(0, Location::RequiresFpuRegister());
2690 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002691 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002692 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002693 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002694
2695 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002696 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002697 }
2698}
2699
2700void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2701 LocationSummary* locations = mul->GetLocations();
2702 Location out = locations->Out();
2703 Location first = locations->InAt(0);
2704 Location second = locations->InAt(1);
2705 switch (mul->GetResultType()) {
2706 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002707 __ mul(out.AsRegister<Register>(),
2708 first.AsRegister<Register>(),
2709 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002710 break;
2711 }
2712 case Primitive::kPrimLong: {
2713 Register out_hi = out.AsRegisterPairHigh<Register>();
2714 Register out_lo = out.AsRegisterPairLow<Register>();
2715 Register in1_hi = first.AsRegisterPairHigh<Register>();
2716 Register in1_lo = first.AsRegisterPairLow<Register>();
2717 Register in2_hi = second.AsRegisterPairHigh<Register>();
2718 Register in2_lo = second.AsRegisterPairLow<Register>();
2719
2720 // Extra checks to protect caused by the existence of R1_R2.
2721 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2722 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2723 DCHECK_NE(out_hi, in1_lo);
2724 DCHECK_NE(out_hi, in2_lo);
2725
2726 // input: in1 - 64 bits, in2 - 64 bits
2727 // output: out
2728 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2729 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2730 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2731
2732 // IP <- in1.lo * in2.hi
2733 __ mul(IP, in1_lo, in2_hi);
2734 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2735 __ mla(out_hi, in1_hi, in2_lo, IP);
2736 // out.lo <- (in1.lo * in2.lo)[31:0];
2737 __ umull(out_lo, IP, in1_lo, in2_lo);
2738 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2739 __ add(out_hi, out_hi, ShifterOperand(IP));
2740 break;
2741 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002742
2743 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002744 __ vmuls(out.AsFpuRegister<SRegister>(),
2745 first.AsFpuRegister<SRegister>(),
2746 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002747 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002748 }
2749
2750 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002751 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2752 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2753 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002754 break;
2755 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002756
2757 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002758 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002759 }
2760}
2761
Zheng Xuc6667102015-05-15 16:08:45 +08002762void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2763 DCHECK(instruction->IsDiv() || instruction->IsRem());
2764 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2765
2766 LocationSummary* locations = instruction->GetLocations();
2767 Location second = locations->InAt(1);
2768 DCHECK(second.IsConstant());
2769
2770 Register out = locations->Out().AsRegister<Register>();
2771 Register dividend = locations->InAt(0).AsRegister<Register>();
2772 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2773 DCHECK(imm == 1 || imm == -1);
2774
2775 if (instruction->IsRem()) {
2776 __ LoadImmediate(out, 0);
2777 } else {
2778 if (imm == 1) {
2779 __ Mov(out, dividend);
2780 } else {
2781 __ rsb(out, dividend, ShifterOperand(0));
2782 }
2783 }
2784}
2785
2786void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2787 DCHECK(instruction->IsDiv() || instruction->IsRem());
2788 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2789
2790 LocationSummary* locations = instruction->GetLocations();
2791 Location second = locations->InAt(1);
2792 DCHECK(second.IsConstant());
2793
2794 Register out = locations->Out().AsRegister<Register>();
2795 Register dividend = locations->InAt(0).AsRegister<Register>();
2796 Register temp = locations->GetTemp(0).AsRegister<Register>();
2797 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002798 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002799 int ctz_imm = CTZ(abs_imm);
2800
2801 if (ctz_imm == 1) {
2802 __ Lsr(temp, dividend, 32 - ctz_imm);
2803 } else {
2804 __ Asr(temp, dividend, 31);
2805 __ Lsr(temp, temp, 32 - ctz_imm);
2806 }
2807 __ add(out, temp, ShifterOperand(dividend));
2808
2809 if (instruction->IsDiv()) {
2810 __ Asr(out, out, ctz_imm);
2811 if (imm < 0) {
2812 __ rsb(out, out, ShifterOperand(0));
2813 }
2814 } else {
2815 __ ubfx(out, out, 0, ctz_imm);
2816 __ sub(out, out, ShifterOperand(temp));
2817 }
2818}
2819
2820void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2821 DCHECK(instruction->IsDiv() || instruction->IsRem());
2822 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2823
2824 LocationSummary* locations = instruction->GetLocations();
2825 Location second = locations->InAt(1);
2826 DCHECK(second.IsConstant());
2827
2828 Register out = locations->Out().AsRegister<Register>();
2829 Register dividend = locations->InAt(0).AsRegister<Register>();
2830 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2831 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2832 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2833
2834 int64_t magic;
2835 int shift;
2836 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2837
2838 __ LoadImmediate(temp1, magic);
2839 __ smull(temp2, temp1, dividend, temp1);
2840
2841 if (imm > 0 && magic < 0) {
2842 __ add(temp1, temp1, ShifterOperand(dividend));
2843 } else if (imm < 0 && magic > 0) {
2844 __ sub(temp1, temp1, ShifterOperand(dividend));
2845 }
2846
2847 if (shift != 0) {
2848 __ Asr(temp1, temp1, shift);
2849 }
2850
2851 if (instruction->IsDiv()) {
2852 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2853 } else {
2854 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2855 // TODO: Strength reduction for mls.
2856 __ LoadImmediate(temp2, imm);
2857 __ mls(out, temp1, temp2, dividend);
2858 }
2859}
2860
2861void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2862 DCHECK(instruction->IsDiv() || instruction->IsRem());
2863 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2864
2865 LocationSummary* locations = instruction->GetLocations();
2866 Location second = locations->InAt(1);
2867 DCHECK(second.IsConstant());
2868
2869 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2870 if (imm == 0) {
2871 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2872 } else if (imm == 1 || imm == -1) {
2873 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002874 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002875 DivRemByPowerOfTwo(instruction);
2876 } else {
2877 DCHECK(imm <= -2 || imm >= 2);
2878 GenerateDivRemWithAnyConstant(instruction);
2879 }
2880}
2881
Calin Juravle7c4954d2014-10-28 16:57:40 +00002882void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002883 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2884 if (div->GetResultType() == Primitive::kPrimLong) {
2885 // pLdiv runtime call.
2886 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002887 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2888 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002889 } else if (div->GetResultType() == Primitive::kPrimInt &&
2890 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2891 // pIdivmod runtime call.
2892 call_kind = LocationSummary::kCall;
2893 }
2894
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002895 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2896
Calin Juravle7c4954d2014-10-28 16:57:40 +00002897 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002898 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002899 if (div->InputAt(1)->IsConstant()) {
2900 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002901 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002902 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002903 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
2904 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08002905 // No temp register required.
2906 } else {
2907 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002908 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08002909 locations->AddTemp(Location::RequiresRegister());
2910 }
2911 }
2912 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002913 locations->SetInAt(0, Location::RequiresRegister());
2914 locations->SetInAt(1, Location::RequiresRegister());
2915 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2916 } else {
2917 InvokeRuntimeCallingConvention calling_convention;
2918 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2919 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2920 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2921 // we only need the former.
2922 locations->SetOut(Location::RegisterLocation(R0));
2923 }
Calin Juravled0d48522014-11-04 16:40:20 +00002924 break;
2925 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002926 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002927 InvokeRuntimeCallingConvention calling_convention;
2928 locations->SetInAt(0, Location::RegisterPairLocation(
2929 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2930 locations->SetInAt(1, Location::RegisterPairLocation(
2931 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002932 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002933 break;
2934 }
2935 case Primitive::kPrimFloat:
2936 case Primitive::kPrimDouble: {
2937 locations->SetInAt(0, Location::RequiresFpuRegister());
2938 locations->SetInAt(1, Location::RequiresFpuRegister());
2939 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2940 break;
2941 }
2942
2943 default:
2944 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2945 }
2946}
2947
2948void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2949 LocationSummary* locations = div->GetLocations();
2950 Location out = locations->Out();
2951 Location first = locations->InAt(0);
2952 Location second = locations->InAt(1);
2953
2954 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002955 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002956 if (second.IsConstant()) {
2957 GenerateDivRemConstantIntegral(div);
2958 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002959 __ sdiv(out.AsRegister<Register>(),
2960 first.AsRegister<Register>(),
2961 second.AsRegister<Register>());
2962 } else {
2963 InvokeRuntimeCallingConvention calling_convention;
2964 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2965 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2966 DCHECK_EQ(R0, out.AsRegister<Register>());
2967
2968 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002969 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002970 }
Calin Juravled0d48522014-11-04 16:40:20 +00002971 break;
2972 }
2973
Calin Juravle7c4954d2014-10-28 16:57:40 +00002974 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002975 InvokeRuntimeCallingConvention calling_convention;
2976 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2977 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2978 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2979 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2980 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002981 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002982
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002983 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00002984 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002985 break;
2986 }
2987
2988 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002989 __ vdivs(out.AsFpuRegister<SRegister>(),
2990 first.AsFpuRegister<SRegister>(),
2991 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002992 break;
2993 }
2994
2995 case Primitive::kPrimDouble: {
2996 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2997 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2998 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2999 break;
3000 }
3001
3002 default:
3003 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3004 }
3005}
3006
Calin Juravlebacfec32014-11-14 15:54:36 +00003007void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003008 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003009
3010 // Most remainders are implemented in the runtime.
3011 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08003012 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
3013 // sdiv will be replaced by other instruction sequence.
3014 call_kind = LocationSummary::kNoCall;
3015 } else if ((rem->GetResultType() == Primitive::kPrimInt)
3016 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003017 // Have hardware divide instruction for int, do it with three instructions.
3018 call_kind = LocationSummary::kNoCall;
3019 }
3020
Calin Juravlebacfec32014-11-14 15:54:36 +00003021 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
3022
Calin Juravled2ec87d2014-12-08 14:24:46 +00003023 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003024 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003025 if (rem->InputAt(1)->IsConstant()) {
3026 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00003027 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08003028 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003029 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
3030 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08003031 // No temp register required.
3032 } else {
3033 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003034 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08003035 locations->AddTemp(Location::RequiresRegister());
3036 }
3037 }
3038 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003039 locations->SetInAt(0, Location::RequiresRegister());
3040 locations->SetInAt(1, Location::RequiresRegister());
3041 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3042 locations->AddTemp(Location::RequiresRegister());
3043 } else {
3044 InvokeRuntimeCallingConvention calling_convention;
3045 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3046 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3047 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
3048 // we only need the latter.
3049 locations->SetOut(Location::RegisterLocation(R1));
3050 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003051 break;
3052 }
3053 case Primitive::kPrimLong: {
3054 InvokeRuntimeCallingConvention calling_convention;
3055 locations->SetInAt(0, Location::RegisterPairLocation(
3056 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3057 locations->SetInAt(1, Location::RegisterPairLocation(
3058 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3059 // The runtime helper puts the output in R2,R3.
3060 locations->SetOut(Location::RegisterPairLocation(R2, R3));
3061 break;
3062 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00003063 case Primitive::kPrimFloat: {
3064 InvokeRuntimeCallingConvention calling_convention;
3065 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
3066 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
3067 locations->SetOut(Location::FpuRegisterLocation(S0));
3068 break;
3069 }
3070
Calin Juravlebacfec32014-11-14 15:54:36 +00003071 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003072 InvokeRuntimeCallingConvention calling_convention;
3073 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3074 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
3075 locations->SetInAt(1, Location::FpuRegisterPairLocation(
3076 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
3077 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00003078 break;
3079 }
3080
3081 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003082 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003083 }
3084}
3085
3086void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
3087 LocationSummary* locations = rem->GetLocations();
3088 Location out = locations->Out();
3089 Location first = locations->InAt(0);
3090 Location second = locations->InAt(1);
3091
Calin Juravled2ec87d2014-12-08 14:24:46 +00003092 Primitive::Type type = rem->GetResultType();
3093 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003094 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08003095 if (second.IsConstant()) {
3096 GenerateDivRemConstantIntegral(rem);
3097 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003098 Register reg1 = first.AsRegister<Register>();
3099 Register reg2 = second.AsRegister<Register>();
3100 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003101
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003102 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003103 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003104 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003105 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003106 } else {
3107 InvokeRuntimeCallingConvention calling_convention;
3108 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
3109 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
3110 DCHECK_EQ(R1, out.AsRegister<Register>());
3111
3112 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003113 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07003114 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003115 break;
3116 }
3117
3118 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003119 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003120 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003121 break;
3122 }
3123
Calin Juravled2ec87d2014-12-08 14:24:46 +00003124 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003125 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003126 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00003127 break;
3128 }
3129
Calin Juravlebacfec32014-11-14 15:54:36 +00003130 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003131 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003132 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00003133 break;
3134 }
3135
3136 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003137 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003138 }
3139}
3140
Calin Juravled0d48522014-11-04 16:40:20 +00003141void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003142 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3143 ? LocationSummary::kCallOnSlowPath
3144 : LocationSummary::kNoCall;
3145 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003146 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00003147 if (instruction->HasUses()) {
3148 locations->SetOut(Location::SameAsFirstInput());
3149 }
3150}
3151
3152void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003153 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003154 codegen_->AddSlowPath(slow_path);
3155
3156 LocationSummary* locations = instruction->GetLocations();
3157 Location value = locations->InAt(0);
3158
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003159 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00003160 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003161 case Primitive::kPrimByte:
3162 case Primitive::kPrimChar:
3163 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003164 case Primitive::kPrimInt: {
3165 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003166 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003167 } else {
3168 DCHECK(value.IsConstant()) << value;
3169 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3170 __ b(slow_path->GetEntryLabel());
3171 }
3172 }
3173 break;
3174 }
3175 case Primitive::kPrimLong: {
3176 if (value.IsRegisterPair()) {
3177 __ orrs(IP,
3178 value.AsRegisterPairLow<Register>(),
3179 ShifterOperand(value.AsRegisterPairHigh<Register>()));
3180 __ b(slow_path->GetEntryLabel(), EQ);
3181 } else {
3182 DCHECK(value.IsConstant()) << value;
3183 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3184 __ b(slow_path->GetEntryLabel());
3185 }
3186 }
3187 break;
3188 default:
3189 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3190 }
3191 }
Calin Juravled0d48522014-11-04 16:40:20 +00003192}
3193
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003194void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
3195 Register in = locations->InAt(0).AsRegister<Register>();
3196 Location rhs = locations->InAt(1);
3197 Register out = locations->Out().AsRegister<Register>();
3198
3199 if (rhs.IsConstant()) {
3200 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
3201 // so map all rotations to a +ve. equivalent in that range.
3202 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
3203 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
3204 if (rot) {
3205 // Rotate, mapping left rotations to right equivalents if necessary.
3206 // (e.g. left by 2 bits == right by 30.)
3207 __ Ror(out, in, rot);
3208 } else if (out != in) {
3209 __ Mov(out, in);
3210 }
3211 } else {
3212 __ Ror(out, in, rhs.AsRegister<Register>());
3213 }
3214}
3215
3216// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
3217// rotates by swapping input regs (effectively rotating by the first 32-bits of
3218// a larger rotation) or flipping direction (thus treating larger right/left
3219// rotations as sub-word sized rotations in the other direction) as appropriate.
3220void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
3221 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
3222 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
3223 Location rhs = locations->InAt(1);
3224 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
3225 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
3226
3227 if (rhs.IsConstant()) {
3228 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
3229 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00003230 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003231 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
3232 // logic below to a simple pair of binary orr.
3233 // (e.g. 34 bits == in_reg swap + 2 bits right.)
3234 if (rot >= kArmBitsPerWord) {
3235 rot -= kArmBitsPerWord;
3236 std::swap(in_reg_hi, in_reg_lo);
3237 }
3238 // Rotate, or mov to out for zero or word size rotations.
3239 if (rot != 0u) {
3240 __ Lsr(out_reg_hi, in_reg_hi, rot);
3241 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
3242 __ Lsr(out_reg_lo, in_reg_lo, rot);
3243 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
3244 } else {
3245 __ Mov(out_reg_lo, in_reg_lo);
3246 __ Mov(out_reg_hi, in_reg_hi);
3247 }
3248 } else {
3249 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
3250 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
3251 Label end;
3252 Label shift_by_32_plus_shift_right;
3253
3254 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
3255 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
3256 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
3257 __ b(&shift_by_32_plus_shift_right, CC);
3258
3259 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
3260 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
3261 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
3262 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3263 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3264 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3265 __ Lsr(shift_left, in_reg_hi, shift_right);
3266 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
3267 __ b(&end);
3268
3269 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
3270 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
3271 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
3272 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
3273 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
3274 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
3275 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
3276 __ Lsl(shift_right, in_reg_hi, shift_left);
3277 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
3278
3279 __ Bind(&end);
3280 }
3281}
Roland Levillain22c49222016-03-18 14:04:28 +00003282
3283void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003284 LocationSummary* locations =
3285 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
3286 switch (ror->GetResultType()) {
3287 case Primitive::kPrimInt: {
3288 locations->SetInAt(0, Location::RequiresRegister());
3289 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
3290 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3291 break;
3292 }
3293 case Primitive::kPrimLong: {
3294 locations->SetInAt(0, Location::RequiresRegister());
3295 if (ror->InputAt(1)->IsConstant()) {
3296 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
3297 } else {
3298 locations->SetInAt(1, Location::RequiresRegister());
3299 locations->AddTemp(Location::RequiresRegister());
3300 locations->AddTemp(Location::RequiresRegister());
3301 }
3302 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3303 break;
3304 }
3305 default:
3306 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
3307 }
3308}
3309
Roland Levillain22c49222016-03-18 14:04:28 +00003310void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003311 LocationSummary* locations = ror->GetLocations();
3312 Primitive::Type type = ror->GetResultType();
3313 switch (type) {
3314 case Primitive::kPrimInt: {
3315 HandleIntegerRotate(locations);
3316 break;
3317 }
3318 case Primitive::kPrimLong: {
3319 HandleLongRotate(locations);
3320 break;
3321 }
3322 default:
3323 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00003324 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00003325 }
3326}
3327
Calin Juravle9aec02f2014-11-18 23:06:35 +00003328void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
3329 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3330
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003331 LocationSummary* locations =
3332 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003333
3334 switch (op->GetResultType()) {
3335 case Primitive::kPrimInt: {
3336 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003337 if (op->InputAt(1)->IsConstant()) {
3338 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3339 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3340 } else {
3341 locations->SetInAt(1, Location::RequiresRegister());
3342 // Make the output overlap, as it will be used to hold the masked
3343 // second input.
3344 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3345 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003346 break;
3347 }
3348 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003349 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003350 if (op->InputAt(1)->IsConstant()) {
3351 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3352 // For simplicity, use kOutputOverlap even though we only require that low registers
3353 // don't clash with high registers which the register allocator currently guarantees.
3354 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3355 } else {
3356 locations->SetInAt(1, Location::RequiresRegister());
3357 locations->AddTemp(Location::RequiresRegister());
3358 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3359 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003360 break;
3361 }
3362 default:
3363 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3364 }
3365}
3366
3367void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3368 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3369
3370 LocationSummary* locations = op->GetLocations();
3371 Location out = locations->Out();
3372 Location first = locations->InAt(0);
3373 Location second = locations->InAt(1);
3374
3375 Primitive::Type type = op->GetResultType();
3376 switch (type) {
3377 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003378 Register out_reg = out.AsRegister<Register>();
3379 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003380 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003381 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00003382 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00003383 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003384 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003385 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003386 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003387 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003388 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003389 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003390 }
3391 } else {
3392 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003393 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00003394 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00003395 __ Mov(out_reg, first_reg);
3396 } else if (op->IsShl()) {
3397 __ Lsl(out_reg, first_reg, shift_value);
3398 } else if (op->IsShr()) {
3399 __ Asr(out_reg, first_reg, shift_value);
3400 } else {
3401 __ Lsr(out_reg, first_reg, shift_value);
3402 }
3403 }
3404 break;
3405 }
3406 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003407 Register o_h = out.AsRegisterPairHigh<Register>();
3408 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003409
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003410 Register high = first.AsRegisterPairHigh<Register>();
3411 Register low = first.AsRegisterPairLow<Register>();
3412
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003413 if (second.IsRegister()) {
3414 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003415
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003416 Register second_reg = second.AsRegister<Register>();
3417
3418 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003419 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003420 // Shift the high part
3421 __ Lsl(o_h, high, o_l);
3422 // Shift the low part and `or` what overflew on the high part
3423 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3424 __ Lsr(temp, low, temp);
3425 __ orr(o_h, o_h, ShifterOperand(temp));
3426 // If the shift is > 32 bits, override the high part
3427 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3428 __ it(PL);
3429 __ Lsl(o_h, low, temp, PL);
3430 // Shift the low part
3431 __ Lsl(o_l, low, o_l);
3432 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003433 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003434 // Shift the low part
3435 __ Lsr(o_l, low, o_h);
3436 // Shift the high part and `or` what underflew on the low part
3437 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3438 __ Lsl(temp, high, temp);
3439 __ orr(o_l, o_l, ShifterOperand(temp));
3440 // If the shift is > 32 bits, override the low part
3441 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3442 __ it(PL);
3443 __ Asr(o_l, high, temp, PL);
3444 // Shift the high part
3445 __ Asr(o_h, high, o_h);
3446 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00003447 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003448 // same as Shr except we use `Lsr`s and not `Asr`s
3449 __ Lsr(o_l, low, o_h);
3450 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3451 __ Lsl(temp, high, temp);
3452 __ orr(o_l, o_l, ShifterOperand(temp));
3453 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3454 __ it(PL);
3455 __ Lsr(o_l, high, temp, PL);
3456 __ Lsr(o_h, high, o_h);
3457 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003458 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003459 // Register allocator doesn't create partial overlap.
3460 DCHECK_NE(o_l, high);
3461 DCHECK_NE(o_h, low);
3462 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00003463 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003464 if (shift_value > 32) {
3465 if (op->IsShl()) {
3466 __ Lsl(o_h, low, shift_value - 32);
3467 __ LoadImmediate(o_l, 0);
3468 } else if (op->IsShr()) {
3469 __ Asr(o_l, high, shift_value - 32);
3470 __ Asr(o_h, high, 31);
3471 } else {
3472 __ Lsr(o_l, high, shift_value - 32);
3473 __ LoadImmediate(o_h, 0);
3474 }
3475 } else if (shift_value == 32) {
3476 if (op->IsShl()) {
3477 __ mov(o_h, ShifterOperand(low));
3478 __ LoadImmediate(o_l, 0);
3479 } else if (op->IsShr()) {
3480 __ mov(o_l, ShifterOperand(high));
3481 __ Asr(o_h, high, 31);
3482 } else {
3483 __ mov(o_l, ShifterOperand(high));
3484 __ LoadImmediate(o_h, 0);
3485 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00003486 } else if (shift_value == 1) {
3487 if (op->IsShl()) {
3488 __ Lsls(o_l, low, 1);
3489 __ adc(o_h, high, ShifterOperand(high));
3490 } else if (op->IsShr()) {
3491 __ Asrs(o_h, high, 1);
3492 __ Rrx(o_l, low);
3493 } else {
3494 __ Lsrs(o_h, high, 1);
3495 __ Rrx(o_l, low);
3496 }
3497 } else {
3498 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003499 if (op->IsShl()) {
3500 __ Lsl(o_h, high, shift_value);
3501 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3502 __ Lsl(o_l, low, shift_value);
3503 } else if (op->IsShr()) {
3504 __ Lsr(o_l, low, shift_value);
3505 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3506 __ Asr(o_h, high, shift_value);
3507 } else {
3508 __ Lsr(o_l, low, shift_value);
3509 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3510 __ Lsr(o_h, high, shift_value);
3511 }
3512 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003513 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003514 break;
3515 }
3516 default:
3517 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003518 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003519 }
3520}
3521
3522void LocationsBuilderARM::VisitShl(HShl* shl) {
3523 HandleShift(shl);
3524}
3525
3526void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3527 HandleShift(shl);
3528}
3529
3530void LocationsBuilderARM::VisitShr(HShr* shr) {
3531 HandleShift(shr);
3532}
3533
3534void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3535 HandleShift(shr);
3536}
3537
3538void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3539 HandleShift(ushr);
3540}
3541
3542void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3543 HandleShift(ushr);
3544}
3545
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003546void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003547 LocationSummary* locations =
3548 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
David Brazdil6de19382016-01-08 17:37:10 +00003549 if (instruction->IsStringAlloc()) {
3550 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
3551 } else {
3552 InvokeRuntimeCallingConvention calling_convention;
3553 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3554 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3555 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003556 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003557}
3558
3559void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003560 // Note: if heap poisoning is enabled, the entry point takes cares
3561 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00003562 if (instruction->IsStringAlloc()) {
3563 // String is allocated through StringFactory. Call NewEmptyString entry point.
3564 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
3565 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize);
3566 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
3567 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
3568 __ blx(LR);
3569 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3570 } else {
3571 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3572 instruction,
3573 instruction->GetDexPc(),
3574 nullptr);
3575 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
3576 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003577}
3578
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003579void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3580 LocationSummary* locations =
3581 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3582 InvokeRuntimeCallingConvention calling_convention;
3583 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003584 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003585 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003586 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003587}
3588
3589void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3590 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003591 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003592 // Note: if heap poisoning is enabled, the entry point takes cares
3593 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003594 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003595 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003596 instruction->GetDexPc(),
3597 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00003598 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003599}
3600
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003601void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003602 LocationSummary* locations =
3603 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003604 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3605 if (location.IsStackSlot()) {
3606 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3607 } else if (location.IsDoubleStackSlot()) {
3608 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003609 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003610 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003611}
3612
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003613void InstructionCodeGeneratorARM::VisitParameterValue(
3614 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003615 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003616}
3617
3618void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3619 LocationSummary* locations =
3620 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3621 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3622}
3623
3624void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3625 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003626}
3627
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003628void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003629 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003630 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003631 locations->SetInAt(0, Location::RequiresRegister());
3632 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003633}
3634
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003635void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3636 LocationSummary* locations = not_->GetLocations();
3637 Location out = locations->Out();
3638 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003639 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003640 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003641 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003642 break;
3643
3644 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003645 __ mvn(out.AsRegisterPairLow<Register>(),
3646 ShifterOperand(in.AsRegisterPairLow<Register>()));
3647 __ mvn(out.AsRegisterPairHigh<Register>(),
3648 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003649 break;
3650
3651 default:
3652 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3653 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003654}
3655
David Brazdil66d126e2015-04-03 16:02:44 +01003656void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3657 LocationSummary* locations =
3658 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3659 locations->SetInAt(0, Location::RequiresRegister());
3660 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3661}
3662
3663void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003664 LocationSummary* locations = bool_not->GetLocations();
3665 Location out = locations->Out();
3666 Location in = locations->InAt(0);
3667 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3668}
3669
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003670void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003671 LocationSummary* locations =
3672 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003673 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003674 case Primitive::kPrimBoolean:
3675 case Primitive::kPrimByte:
3676 case Primitive::kPrimShort:
3677 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003678 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00003679 case Primitive::kPrimLong: {
3680 locations->SetInAt(0, Location::RequiresRegister());
3681 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003682 // Output overlaps because it is written before doing the low comparison.
3683 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003684 break;
3685 }
3686 case Primitive::kPrimFloat:
3687 case Primitive::kPrimDouble: {
3688 locations->SetInAt(0, Location::RequiresFpuRegister());
3689 locations->SetInAt(1, Location::RequiresFpuRegister());
3690 locations->SetOut(Location::RequiresRegister());
3691 break;
3692 }
3693 default:
3694 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3695 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003696}
3697
3698void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003699 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003700 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003701 Location left = locations->InAt(0);
3702 Location right = locations->InAt(1);
3703
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003704 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003705 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00003706 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00003707 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00003708 case Primitive::kPrimBoolean:
3709 case Primitive::kPrimByte:
3710 case Primitive::kPrimShort:
3711 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08003712 case Primitive::kPrimInt: {
3713 __ LoadImmediate(out, 0);
3714 __ cmp(left.AsRegister<Register>(),
3715 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
3716 less_cond = LT;
3717 break;
3718 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003719 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003720 __ cmp(left.AsRegisterPairHigh<Register>(),
3721 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003722 __ b(&less, LT);
3723 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003724 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003725 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003726 __ cmp(left.AsRegisterPairLow<Register>(),
3727 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003728 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00003729 break;
3730 }
3731 case Primitive::kPrimFloat:
3732 case Primitive::kPrimDouble: {
3733 __ LoadImmediate(out, 0);
3734 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003735 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003736 } else {
3737 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3738 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3739 }
3740 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00003741 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003742 break;
3743 }
3744 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003745 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00003746 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003747 }
Aart Bika19616e2016-02-01 18:57:58 -08003748
Calin Juravleddb7df22014-11-25 20:56:51 +00003749 __ b(&done, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00003750 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00003751
3752 __ Bind(&greater);
3753 __ LoadImmediate(out, 1);
3754 __ b(&done);
3755
3756 __ Bind(&less);
3757 __ LoadImmediate(out, -1);
3758
3759 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003760}
3761
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003762void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003763 LocationSummary* locations =
3764 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003765 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3766 locations->SetInAt(i, Location::Any());
3767 }
3768 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003769}
3770
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003771void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003772 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003773}
3774
Roland Levillainc9285912015-12-18 10:38:42 +00003775void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3776 // TODO (ported from quick): revisit ARM barrier kinds.
3777 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00003778 switch (kind) {
3779 case MemBarrierKind::kAnyStore:
3780 case MemBarrierKind::kLoadAny:
3781 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003782 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003783 break;
3784 }
3785 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003786 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003787 break;
3788 }
3789 default:
3790 LOG(FATAL) << "Unexpected memory barrier " << kind;
3791 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003792 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003793}
3794
3795void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3796 uint32_t offset,
3797 Register out_lo,
3798 Register out_hi) {
3799 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00003800 // Ensure `out_lo` is different from `addr`, so that loading
3801 // `offset` into `out_lo` does not clutter `addr`.
3802 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00003803 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003804 __ add(IP, addr, ShifterOperand(out_lo));
3805 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003806 }
3807 __ ldrexd(out_lo, out_hi, addr);
3808}
3809
3810void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3811 uint32_t offset,
3812 Register value_lo,
3813 Register value_hi,
3814 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003815 Register temp2,
3816 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003817 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003818 if (offset != 0) {
3819 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003820 __ add(IP, addr, ShifterOperand(temp1));
3821 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003822 }
3823 __ Bind(&fail);
3824 // We need a load followed by store. (The address used in a STREX instruction must
3825 // be the same as the address in the most recently executed LDREX instruction.)
3826 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003827 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003828 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003829 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003830}
3831
3832void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3833 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3834
Nicolas Geoffray39468442014-09-02 15:17:15 +01003835 LocationSummary* locations =
3836 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003837 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003838
Calin Juravle52c48962014-12-16 17:02:57 +00003839 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003840 if (Primitive::IsFloatingPointType(field_type)) {
3841 locations->SetInAt(1, Location::RequiresFpuRegister());
3842 } else {
3843 locations->SetInAt(1, Location::RequiresRegister());
3844 }
3845
Calin Juravle52c48962014-12-16 17:02:57 +00003846 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003847 bool generate_volatile = field_info.IsVolatile()
3848 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003849 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003850 bool needs_write_barrier =
3851 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003852 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003853 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003854 if (needs_write_barrier) {
3855 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003856 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003857 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003858 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00003859 // - registers need to be consecutive
3860 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00003861 // We don't test for ARM yet, and the assertion makes sure that we
3862 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00003863 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3864
3865 locations->AddTemp(Location::RequiresRegister());
3866 locations->AddTemp(Location::RequiresRegister());
3867 if (field_type == Primitive::kPrimDouble) {
3868 // For doubles we need two more registers to copy the value.
3869 locations->AddTemp(Location::RegisterLocation(R2));
3870 locations->AddTemp(Location::RegisterLocation(R3));
3871 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003872 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003873}
3874
Calin Juravle52c48962014-12-16 17:02:57 +00003875void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003876 const FieldInfo& field_info,
3877 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003878 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3879
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003880 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003881 Register base = locations->InAt(0).AsRegister<Register>();
3882 Location value = locations->InAt(1);
3883
3884 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003885 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003886 Primitive::Type field_type = field_info.GetFieldType();
3887 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003888 bool needs_write_barrier =
3889 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003890
3891 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003892 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00003893 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003894
3895 switch (field_type) {
3896 case Primitive::kPrimBoolean:
3897 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003898 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003899 break;
3900 }
3901
3902 case Primitive::kPrimShort:
3903 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003904 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003905 break;
3906 }
3907
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003908 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003909 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003910 if (kPoisonHeapReferences && needs_write_barrier) {
3911 // Note that in the case where `value` is a null reference,
3912 // we do not enter this block, as a null reference does not
3913 // need poisoning.
3914 DCHECK_EQ(field_type, Primitive::kPrimNot);
3915 Register temp = locations->GetTemp(0).AsRegister<Register>();
3916 __ Mov(temp, value.AsRegister<Register>());
3917 __ PoisonHeapReference(temp);
3918 __ StoreToOffset(kStoreWord, temp, base, offset);
3919 } else {
3920 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3921 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003922 break;
3923 }
3924
3925 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003926 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003927 GenerateWideAtomicStore(base, offset,
3928 value.AsRegisterPairLow<Register>(),
3929 value.AsRegisterPairHigh<Register>(),
3930 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003931 locations->GetTemp(1).AsRegister<Register>(),
3932 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003933 } else {
3934 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003935 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003936 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003937 break;
3938 }
3939
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003940 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003941 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003942 break;
3943 }
3944
3945 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003946 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003947 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003948 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3949 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3950
3951 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3952
3953 GenerateWideAtomicStore(base, offset,
3954 value_reg_lo,
3955 value_reg_hi,
3956 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003957 locations->GetTemp(3).AsRegister<Register>(),
3958 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003959 } else {
3960 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003961 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003962 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003963 break;
3964 }
3965
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003966 case Primitive::kPrimVoid:
3967 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003968 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003969 }
Calin Juravle52c48962014-12-16 17:02:57 +00003970
Calin Juravle77520bc2015-01-12 18:45:46 +00003971 // Longs and doubles are handled in the switch.
3972 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3973 codegen_->MaybeRecordImplicitNullCheck(instruction);
3974 }
3975
3976 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3977 Register temp = locations->GetTemp(0).AsRegister<Register>();
3978 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003979 codegen_->MarkGCCard(
3980 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003981 }
3982
Calin Juravle52c48962014-12-16 17:02:57 +00003983 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00003984 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00003985 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003986}
3987
Calin Juravle52c48962014-12-16 17:02:57 +00003988void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3989 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00003990
3991 bool object_field_get_with_read_barrier =
3992 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003993 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00003994 new (GetGraph()->GetArena()) LocationSummary(instruction,
3995 object_field_get_with_read_barrier ?
3996 LocationSummary::kCallOnSlowPath :
3997 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003998 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003999
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004000 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00004001 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004002 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00004003 // The output overlaps in case of volatile long: we don't want the
4004 // code generated by GenerateWideAtomicLoad to overwrite the
4005 // object's location. Likewise, in the case of an object field get
4006 // with read barriers enabled, we do not want the load to overwrite
4007 // the object's location, as we need it to emit the read barrier.
4008 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
4009 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01004010
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004011 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4012 locations->SetOut(Location::RequiresFpuRegister());
4013 } else {
4014 locations->SetOut(Location::RequiresRegister(),
4015 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
4016 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004017 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00004018 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00004019 // - registers need to be consecutive
4020 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00004021 // We don't test for ARM yet, and the assertion makes sure that we
4022 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00004023 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
4024 locations->AddTemp(Location::RequiresRegister());
4025 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00004026 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4027 // We need a temporary register for the read barrier marking slow
4028 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
4029 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004030 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004031}
4032
Vladimir Markod2b4ca22015-09-14 15:13:26 +01004033Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
4034 Opcode opcode) {
4035 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
4036 if (constant->IsConstant() &&
4037 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
4038 return Location::ConstantLocation(constant->AsConstant());
4039 }
4040 return Location::RequiresRegister();
4041}
4042
4043bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
4044 Opcode opcode) {
4045 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
4046 if (Primitive::Is64BitType(input_cst->GetType())) {
4047 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
4048 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
4049 } else {
4050 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
4051 }
4052}
4053
4054bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
4055 ShifterOperand so;
4056 ArmAssembler* assembler = codegen_->GetAssembler();
4057 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
4058 return true;
4059 }
4060 Opcode neg_opcode = kNoOperand;
4061 switch (opcode) {
4062 case AND:
4063 neg_opcode = BIC;
4064 break;
4065 case ORR:
4066 neg_opcode = ORN;
4067 break;
4068 default:
4069 return false;
4070 }
4071 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
4072}
4073
Calin Juravle52c48962014-12-16 17:02:57 +00004074void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
4075 const FieldInfo& field_info) {
4076 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004077
Calin Juravle52c48962014-12-16 17:02:57 +00004078 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004079 Location base_loc = locations->InAt(0);
4080 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00004081 Location out = locations->Out();
4082 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004083 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00004084 Primitive::Type field_type = field_info.GetFieldType();
4085 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4086
4087 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00004088 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00004089 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004090 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004091
Roland Levillainc9285912015-12-18 10:38:42 +00004092 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00004093 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004094 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004095
Roland Levillainc9285912015-12-18 10:38:42 +00004096 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00004097 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004098 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004099
Roland Levillainc9285912015-12-18 10:38:42 +00004100 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00004101 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004102 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004103
4104 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00004105 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004106 break;
Roland Levillainc9285912015-12-18 10:38:42 +00004107
4108 case Primitive::kPrimNot: {
4109 // /* HeapReference<Object> */ out = *(base + offset)
4110 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4111 Location temp_loc = locations->GetTemp(0);
4112 // Note that a potential implicit null check is handled in this
4113 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
4114 codegen_->GenerateFieldLoadWithBakerReadBarrier(
4115 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
4116 if (is_volatile) {
4117 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4118 }
4119 } else {
4120 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
4121 codegen_->MaybeRecordImplicitNullCheck(instruction);
4122 if (is_volatile) {
4123 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4124 }
4125 // If read barriers are enabled, emit read barriers other than
4126 // Baker's using a slow path (and also unpoison the loaded
4127 // reference, if heap poisoning is enabled).
4128 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
4129 }
4130 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004131 }
4132
Roland Levillainc9285912015-12-18 10:38:42 +00004133 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00004134 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004135 GenerateWideAtomicLoad(base, offset,
4136 out.AsRegisterPairLow<Register>(),
4137 out.AsRegisterPairHigh<Register>());
4138 } else {
4139 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
4140 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004141 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004142
Roland Levillainc9285912015-12-18 10:38:42 +00004143 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00004144 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004145 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004146
4147 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00004148 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00004149 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00004150 Register lo = locations->GetTemp(0).AsRegister<Register>();
4151 Register hi = locations->GetTemp(1).AsRegister<Register>();
4152 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00004153 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004154 __ vmovdrr(out_reg, lo, hi);
4155 } else {
4156 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004157 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004158 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00004159 break;
4160 }
4161
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004162 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00004163 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004164 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004165 }
Calin Juravle52c48962014-12-16 17:02:57 +00004166
Roland Levillainc9285912015-12-18 10:38:42 +00004167 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
4168 // Potential implicit null checks, in the case of reference or
4169 // double fields, are handled in the previous switch statement.
4170 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00004171 codegen_->MaybeRecordImplicitNullCheck(instruction);
4172 }
4173
Calin Juravle52c48962014-12-16 17:02:57 +00004174 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00004175 if (field_type == Primitive::kPrimNot) {
4176 // Memory barriers, in the case of references, are also handled
4177 // in the previous switch statement.
4178 } else {
4179 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4180 }
Roland Levillain4d027112015-07-01 15:41:14 +01004181 }
Calin Juravle52c48962014-12-16 17:02:57 +00004182}
4183
4184void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4185 HandleFieldSet(instruction, instruction->GetFieldInfo());
4186}
4187
4188void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004189 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004190}
4191
4192void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4193 HandleFieldGet(instruction, instruction->GetFieldInfo());
4194}
4195
4196void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4197 HandleFieldGet(instruction, instruction->GetFieldInfo());
4198}
4199
4200void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4201 HandleFieldGet(instruction, instruction->GetFieldInfo());
4202}
4203
4204void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4205 HandleFieldGet(instruction, instruction->GetFieldInfo());
4206}
4207
4208void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4209 HandleFieldSet(instruction, instruction->GetFieldInfo());
4210}
4211
4212void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004213 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004214}
4215
Calin Juravlee460d1d2015-09-29 04:52:17 +01004216void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
4217 HUnresolvedInstanceFieldGet* instruction) {
4218 FieldAccessCallingConventionARM calling_convention;
4219 codegen_->CreateUnresolvedFieldLocationSummary(
4220 instruction, instruction->GetFieldType(), calling_convention);
4221}
4222
4223void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
4224 HUnresolvedInstanceFieldGet* instruction) {
4225 FieldAccessCallingConventionARM calling_convention;
4226 codegen_->GenerateUnresolvedFieldAccess(instruction,
4227 instruction->GetFieldType(),
4228 instruction->GetFieldIndex(),
4229 instruction->GetDexPc(),
4230 calling_convention);
4231}
4232
4233void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
4234 HUnresolvedInstanceFieldSet* instruction) {
4235 FieldAccessCallingConventionARM calling_convention;
4236 codegen_->CreateUnresolvedFieldLocationSummary(
4237 instruction, instruction->GetFieldType(), calling_convention);
4238}
4239
4240void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
4241 HUnresolvedInstanceFieldSet* instruction) {
4242 FieldAccessCallingConventionARM calling_convention;
4243 codegen_->GenerateUnresolvedFieldAccess(instruction,
4244 instruction->GetFieldType(),
4245 instruction->GetFieldIndex(),
4246 instruction->GetDexPc(),
4247 calling_convention);
4248}
4249
4250void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
4251 HUnresolvedStaticFieldGet* instruction) {
4252 FieldAccessCallingConventionARM calling_convention;
4253 codegen_->CreateUnresolvedFieldLocationSummary(
4254 instruction, instruction->GetFieldType(), calling_convention);
4255}
4256
4257void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
4258 HUnresolvedStaticFieldGet* instruction) {
4259 FieldAccessCallingConventionARM calling_convention;
4260 codegen_->GenerateUnresolvedFieldAccess(instruction,
4261 instruction->GetFieldType(),
4262 instruction->GetFieldIndex(),
4263 instruction->GetDexPc(),
4264 calling_convention);
4265}
4266
4267void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
4268 HUnresolvedStaticFieldSet* instruction) {
4269 FieldAccessCallingConventionARM calling_convention;
4270 codegen_->CreateUnresolvedFieldLocationSummary(
4271 instruction, instruction->GetFieldType(), calling_convention);
4272}
4273
4274void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
4275 HUnresolvedStaticFieldSet* instruction) {
4276 FieldAccessCallingConventionARM calling_convention;
4277 codegen_->GenerateUnresolvedFieldAccess(instruction,
4278 instruction->GetFieldType(),
4279 instruction->GetFieldIndex(),
4280 instruction->GetDexPc(),
4281 calling_convention);
4282}
4283
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004284void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004285 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4286 ? LocationSummary::kCallOnSlowPath
4287 : LocationSummary::kNoCall;
4288 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00004289 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004290 if (instruction->HasUses()) {
4291 locations->SetOut(Location::SameAsFirstInput());
4292 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004293}
4294
Calin Juravle2ae48182016-03-16 14:05:09 +00004295void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
4296 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004297 return;
4298 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004299 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004300
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004301 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004302 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004303}
4304
Calin Juravle2ae48182016-03-16 14:05:09 +00004305void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004306 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004307 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004308
4309 LocationSummary* locations = instruction->GetLocations();
4310 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004311
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004312 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004313}
4314
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004315void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004316 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004317}
4318
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004319void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00004320 bool object_array_get_with_read_barrier =
4321 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004322 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00004323 new (GetGraph()->GetArena()) LocationSummary(instruction,
4324 object_array_get_with_read_barrier ?
4325 LocationSummary::kCallOnSlowPath :
4326 LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004327 locations->SetInAt(0, Location::RequiresRegister());
4328 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004329 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4330 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4331 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004332 // The output overlaps in the case of an object array get with
4333 // read barriers enabled: we do not want the move to overwrite the
4334 // array's location, as we need it to emit the read barrier.
4335 locations->SetOut(
4336 Location::RequiresRegister(),
4337 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004338 }
Roland Levillainc9285912015-12-18 10:38:42 +00004339 // We need a temporary register for the read barrier marking slow
4340 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
4341 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
4342 locations->AddTemp(Location::RequiresRegister());
4343 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004344}
4345
4346void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
4347 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004348 Location obj_loc = locations->InAt(0);
4349 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004350 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00004351 Location out_loc = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004352
Roland Levillainc9285912015-12-18 10:38:42 +00004353 Primitive::Type type = instruction->GetType();
Roland Levillain4d027112015-07-01 15:41:14 +01004354 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004355 case Primitive::kPrimBoolean: {
4356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004357 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004359 size_t offset =
4360 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004361 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
4362 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004363 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004364 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
4365 }
4366 break;
4367 }
4368
4369 case Primitive::kPrimByte: {
4370 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004371 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004372 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004373 size_t offset =
4374 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004375 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
4376 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004377 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004378 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
4379 }
4380 break;
4381 }
4382
4383 case Primitive::kPrimShort: {
4384 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004385 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004386 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004387 size_t offset =
4388 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004389 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
4390 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004391 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004392 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
4393 }
4394 break;
4395 }
4396
4397 case Primitive::kPrimChar: {
4398 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004399 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004400 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004401 size_t offset =
4402 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004403 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
4404 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004406 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
4407 }
4408 break;
4409 }
4410
Roland Levillainc9285912015-12-18 10:38:42 +00004411 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004412 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004413 Register out = out_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004414 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004415 size_t offset =
4416 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004417 __ LoadFromOffset(kLoadWord, out, obj, offset);
4418 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004419 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004420 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4421 }
4422 break;
4423 }
4424
Roland Levillainc9285912015-12-18 10:38:42 +00004425 case Primitive::kPrimNot: {
4426 static_assert(
4427 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4428 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4429 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4430 // /* HeapReference<Object> */ out =
4431 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
4432 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4433 Location temp = locations->GetTemp(0);
4434 // Note that a potential implicit null check is handled in this
4435 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
4436 codegen_->GenerateArrayLoadWithBakerReadBarrier(
4437 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
4438 } else {
4439 Register out = out_loc.AsRegister<Register>();
4440 if (index.IsConstant()) {
4441 size_t offset =
4442 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4443 __ LoadFromOffset(kLoadWord, out, obj, offset);
4444 codegen_->MaybeRecordImplicitNullCheck(instruction);
4445 // If read barriers are enabled, emit read barriers other than
4446 // Baker's using a slow path (and also unpoison the loaded
4447 // reference, if heap poisoning is enabled).
4448 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
4449 } else {
4450 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4451 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
4452 codegen_->MaybeRecordImplicitNullCheck(instruction);
4453 // If read barriers are enabled, emit read barriers other than
4454 // Baker's using a slow path (and also unpoison the loaded
4455 // reference, if heap poisoning is enabled).
4456 codegen_->MaybeGenerateReadBarrierSlow(
4457 instruction, out_loc, out_loc, obj_loc, data_offset, index);
4458 }
4459 }
4460 break;
4461 }
4462
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004463 case Primitive::kPrimLong: {
4464 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004465 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004466 size_t offset =
4467 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004468 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004469 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004470 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004471 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004472 }
4473 break;
4474 }
4475
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004476 case Primitive::kPrimFloat: {
4477 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004478 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004479 if (index.IsConstant()) {
4480 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004481 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004482 } else {
4483 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00004484 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004485 }
4486 break;
4487 }
4488
4489 case Primitive::kPrimDouble: {
4490 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Roland Levillainc9285912015-12-18 10:38:42 +00004491 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004492 if (index.IsConstant()) {
4493 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00004494 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004495 } else {
4496 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00004497 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004498 }
4499 break;
4500 }
4501
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004502 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004503 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004504 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004505 }
Roland Levillain4d027112015-07-01 15:41:14 +01004506
4507 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00004508 // Potential implicit null checks, in the case of reference
4509 // arrays, are handled in the previous switch statement.
4510 } else {
4511 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004512 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004513}
4514
4515void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004516 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004517
4518 bool needs_write_barrier =
4519 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00004520 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
4521 bool object_array_set_with_read_barrier =
4522 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004523
Nicolas Geoffray39468442014-09-02 15:17:15 +01004524 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004525 instruction,
Roland Levillain3b359c72015-11-17 19:35:12 +00004526 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
4527 LocationSummary::kCallOnSlowPath :
4528 LocationSummary::kNoCall);
4529
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004530 locations->SetInAt(0, Location::RequiresRegister());
4531 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4532 if (Primitive::IsFloatingPointType(value_type)) {
4533 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004534 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004535 locations->SetInAt(2, Location::RequiresRegister());
4536 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004537 if (needs_write_barrier) {
4538 // Temporary registers for the write barrier.
4539 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00004540 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004541 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004542}
4543
4544void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4545 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00004546 Location array_loc = locations->InAt(0);
4547 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004548 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004549 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00004550 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004551 bool needs_write_barrier =
4552 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004553
4554 switch (value_type) {
4555 case Primitive::kPrimBoolean:
4556 case Primitive::kPrimByte: {
4557 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004558 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004559 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004560 size_t offset =
4561 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004562 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004563 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004564 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004565 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4566 }
4567 break;
4568 }
4569
4570 case Primitive::kPrimShort:
4571 case Primitive::kPrimChar: {
4572 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004573 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004574 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004575 size_t offset =
4576 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004577 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004578 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004579 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004580 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4581 }
4582 break;
4583 }
4584
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004585 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004586 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00004587 Location value_loc = locations->InAt(2);
4588 Register value = value_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004589 Register source = value;
4590
4591 if (instruction->InputAt(2)->IsNullConstant()) {
4592 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004593 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004594 size_t offset =
4595 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004596 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004597 } else {
4598 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004599 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004600 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004601 }
Roland Levillain1407ee72016-01-08 15:56:19 +00004602 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00004603 DCHECK(!needs_write_barrier);
4604 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004605 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004606 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004607
4608 DCHECK(needs_write_barrier);
4609 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4610 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4611 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4612 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4613 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4614 Label done;
4615 SlowPathCode* slow_path = nullptr;
4616
Roland Levillain3b359c72015-11-17 19:35:12 +00004617 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004618 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4619 codegen_->AddSlowPath(slow_path);
4620 if (instruction->GetValueCanBeNull()) {
4621 Label non_zero;
4622 __ CompareAndBranchIfNonZero(value, &non_zero);
4623 if (index.IsConstant()) {
4624 size_t offset =
4625 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4626 __ StoreToOffset(kStoreWord, value, array, offset);
4627 } else {
4628 DCHECK(index.IsRegister()) << index;
4629 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4630 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4631 }
4632 codegen_->MaybeRecordImplicitNullCheck(instruction);
4633 __ b(&done);
4634 __ Bind(&non_zero);
4635 }
4636
Roland Levillain3b359c72015-11-17 19:35:12 +00004637 if (kEmitCompilerReadBarrier) {
4638 // When read barriers are enabled, the type checking
4639 // instrumentation requires two read barriers:
4640 //
4641 // __ Mov(temp2, temp1);
4642 // // /* HeapReference<Class> */ temp1 = temp1->component_type_
4643 // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004644 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004645 // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
4646 //
4647 // // /* HeapReference<Class> */ temp2 = value->klass_
4648 // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
Roland Levillainc9285912015-12-18 10:38:42 +00004649 // codegen_->GenerateReadBarrierSlow(
Roland Levillain3b359c72015-11-17 19:35:12 +00004650 // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
4651 //
4652 // __ cmp(temp1, ShifterOperand(temp2));
4653 //
4654 // However, the second read barrier may trash `temp`, as it
4655 // is a temporary register, and as such would not be saved
4656 // along with live registers before calling the runtime (nor
4657 // restored afterwards). So in this case, we bail out and
4658 // delegate the work to the array set slow path.
4659 //
4660 // TODO: Extend the register allocator to support a new
4661 // "(locally) live temp" location so as to avoid always
4662 // going into the slow path when read barriers are enabled.
4663 __ b(slow_path->GetEntryLabel());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004664 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00004665 // /* HeapReference<Class> */ temp1 = array->klass_
4666 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4667 codegen_->MaybeRecordImplicitNullCheck(instruction);
4668 __ MaybeUnpoisonHeapReference(temp1);
4669
4670 // /* HeapReference<Class> */ temp1 = temp1->component_type_
4671 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4672 // /* HeapReference<Class> */ temp2 = value->klass_
4673 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4674 // If heap poisoning is enabled, no need to unpoison `temp1`
4675 // nor `temp2`, as we are comparing two poisoned references.
4676 __ cmp(temp1, ShifterOperand(temp2));
4677
4678 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4679 Label do_put;
4680 __ b(&do_put, EQ);
4681 // If heap poisoning is enabled, the `temp1` reference has
4682 // not been unpoisoned yet; unpoison it now.
4683 __ MaybeUnpoisonHeapReference(temp1);
4684
4685 // /* HeapReference<Class> */ temp1 = temp1->super_class_
4686 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4687 // If heap poisoning is enabled, no need to unpoison
4688 // `temp1`, as we are comparing against null below.
4689 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4690 __ Bind(&do_put);
4691 } else {
4692 __ b(slow_path->GetEntryLabel(), NE);
4693 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004694 }
4695 }
4696
4697 if (kPoisonHeapReferences) {
4698 // Note that in the case where `value` is a null reference,
4699 // we do not enter this block, as a null reference does not
4700 // need poisoning.
4701 DCHECK_EQ(value_type, Primitive::kPrimNot);
4702 __ Mov(temp1, value);
4703 __ PoisonHeapReference(temp1);
4704 source = temp1;
4705 }
4706
4707 if (index.IsConstant()) {
4708 size_t offset =
4709 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4710 __ StoreToOffset(kStoreWord, source, array, offset);
4711 } else {
4712 DCHECK(index.IsRegister()) << index;
4713 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4714 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4715 }
4716
Roland Levillain3b359c72015-11-17 19:35:12 +00004717 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004718 codegen_->MaybeRecordImplicitNullCheck(instruction);
4719 }
4720
4721 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4722
4723 if (done.IsLinked()) {
4724 __ Bind(&done);
4725 }
4726
4727 if (slow_path != nullptr) {
4728 __ Bind(slow_path->GetExitLabel());
4729 }
4730
4731 break;
4732 }
4733
4734 case Primitive::kPrimInt: {
4735 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4736 Register value = locations->InAt(2).AsRegister<Register>();
4737 if (index.IsConstant()) {
4738 size_t offset =
4739 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4740 __ StoreToOffset(kStoreWord, value, array, offset);
4741 } else {
4742 DCHECK(index.IsRegister()) << index;
4743 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4744 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4745 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004746 break;
4747 }
4748
4749 case Primitive::kPrimLong: {
4750 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004751 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004752 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004753 size_t offset =
4754 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004755 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004756 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004757 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004758 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004759 }
4760 break;
4761 }
4762
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004763 case Primitive::kPrimFloat: {
4764 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4765 Location value = locations->InAt(2);
4766 DCHECK(value.IsFpuRegister());
4767 if (index.IsConstant()) {
4768 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004769 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004770 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004771 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004772 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4773 }
4774 break;
4775 }
4776
4777 case Primitive::kPrimDouble: {
4778 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4779 Location value = locations->InAt(2);
4780 DCHECK(value.IsFpuRegisterPair());
4781 if (index.IsConstant()) {
4782 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004783 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004784 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004785 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004786 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4787 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004788
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004789 break;
4790 }
4791
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004792 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004793 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004794 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004795 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004796
Roland Levillain80e67092016-01-08 16:04:55 +00004797 // Objects are handled in the switch.
4798 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004799 codegen_->MaybeRecordImplicitNullCheck(instruction);
4800 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004801}
4802
4803void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004804 LocationSummary* locations =
4805 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004806 locations->SetInAt(0, Location::RequiresRegister());
4807 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004808}
4809
4810void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4811 LocationSummary* locations = instruction->GetLocations();
4812 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004813 Register obj = locations->InAt(0).AsRegister<Register>();
4814 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004815 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004816 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004817}
4818
4819void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004820 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4821 ? LocationSummary::kCallOnSlowPath
4822 : LocationSummary::kNoCall;
4823 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004824 locations->SetInAt(0, Location::RequiresRegister());
4825 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004826 if (instruction->HasUses()) {
4827 locations->SetOut(Location::SameAsFirstInput());
4828 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004829}
4830
4831void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4832 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004833 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004834 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004835 codegen_->AddSlowPath(slow_path);
4836
Roland Levillain271ab9c2014-11-27 15:23:57 +00004837 Register index = locations->InAt(0).AsRegister<Register>();
4838 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004839
4840 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004841 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004842}
4843
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004844void CodeGeneratorARM::MarkGCCard(Register temp,
4845 Register card,
4846 Register object,
4847 Register value,
4848 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004849 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004850 if (can_be_null) {
4851 __ CompareAndBranchIfZero(value, &is_null);
4852 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004853 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4854 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4855 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004856 if (can_be_null) {
4857 __ Bind(&is_null);
4858 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004859}
4860
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004861void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004862 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004863}
4864
4865void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004866 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4867}
4868
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004869void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4870 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4871}
4872
4873void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004874 HBasicBlock* block = instruction->GetBlock();
4875 if (block->GetLoopInformation() != nullptr) {
4876 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4877 // The back edge will generate the suspend check.
4878 return;
4879 }
4880 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4881 // The goto will generate the suspend check.
4882 return;
4883 }
4884 GenerateSuspendCheck(instruction, nullptr);
4885}
4886
4887void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4888 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004889 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004890 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4891 if (slow_path == nullptr) {
4892 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4893 instruction->SetSlowPath(slow_path);
4894 codegen_->AddSlowPath(slow_path);
4895 if (successor != nullptr) {
4896 DCHECK(successor->IsLoopHeader());
4897 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4898 }
4899 } else {
4900 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4901 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004902
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004903 __ LoadFromOffset(
4904 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004905 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004906 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004907 __ Bind(slow_path->GetReturnLabel());
4908 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004909 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004910 __ b(slow_path->GetEntryLabel());
4911 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004912}
4913
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004914ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4915 return codegen_->GetAssembler();
4916}
4917
4918void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004919 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004920 Location source = move->GetSource();
4921 Location destination = move->GetDestination();
4922
4923 if (source.IsRegister()) {
4924 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004925 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004926 } else if (destination.IsFpuRegister()) {
4927 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004928 } else {
4929 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004930 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004931 SP, destination.GetStackIndex());
4932 }
4933 } else if (source.IsStackSlot()) {
4934 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004935 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004936 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004937 } else if (destination.IsFpuRegister()) {
4938 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004939 } else {
4940 DCHECK(destination.IsStackSlot());
4941 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4942 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4943 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004944 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004945 if (destination.IsRegister()) {
4946 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
4947 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004948 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004949 } else {
4950 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004951 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4952 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004953 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004954 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004955 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4956 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004957 } else if (destination.IsRegisterPair()) {
4958 DCHECK(ExpectedPairLayout(destination));
4959 __ LoadFromOffset(
4960 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4961 } else {
4962 DCHECK(destination.IsFpuRegisterPair()) << destination;
4963 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4964 SP,
4965 source.GetStackIndex());
4966 }
4967 } else if (source.IsRegisterPair()) {
4968 if (destination.IsRegisterPair()) {
4969 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4970 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00004971 } else if (destination.IsFpuRegisterPair()) {
4972 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4973 source.AsRegisterPairLow<Register>(),
4974 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004975 } else {
4976 DCHECK(destination.IsDoubleStackSlot()) << destination;
4977 DCHECK(ExpectedPairLayout(source));
4978 __ StoreToOffset(
4979 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4980 }
4981 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00004982 if (destination.IsRegisterPair()) {
4983 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4984 destination.AsRegisterPairHigh<Register>(),
4985 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4986 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004987 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4988 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4989 } else {
4990 DCHECK(destination.IsDoubleStackSlot()) << destination;
4991 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4992 SP,
4993 destination.GetStackIndex());
4994 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004995 } else {
4996 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004997 HConstant* constant = source.GetConstant();
4998 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4999 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005000 if (destination.IsRegister()) {
5001 __ LoadImmediate(destination.AsRegister<Register>(), value);
5002 } else {
5003 DCHECK(destination.IsStackSlot());
5004 __ LoadImmediate(IP, value);
5005 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5006 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005007 } else if (constant->IsLongConstant()) {
5008 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005009 if (destination.IsRegisterPair()) {
5010 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
5011 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005012 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005013 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005014 __ LoadImmediate(IP, Low32Bits(value));
5015 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5016 __ LoadImmediate(IP, High32Bits(value));
5017 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5018 }
5019 } else if (constant->IsDoubleConstant()) {
5020 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005021 if (destination.IsFpuRegisterPair()) {
5022 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005023 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005024 DCHECK(destination.IsDoubleStackSlot()) << destination;
5025 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005026 __ LoadImmediate(IP, Low32Bits(int_value));
5027 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5028 __ LoadImmediate(IP, High32Bits(int_value));
5029 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
5030 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005031 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00005032 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005033 float value = constant->AsFloatConstant()->GetValue();
5034 if (destination.IsFpuRegister()) {
5035 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
5036 } else {
5037 DCHECK(destination.IsStackSlot());
5038 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
5039 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
5040 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01005041 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005042 }
5043}
5044
5045void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
5046 __ Mov(IP, reg);
5047 __ LoadFromOffset(kLoadWord, reg, SP, mem);
5048 __ StoreToOffset(kStoreWord, IP, SP, mem);
5049}
5050
5051void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
5052 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
5053 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
5054 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
5055 SP, mem1 + stack_offset);
5056 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
5057 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
5058 SP, mem2 + stack_offset);
5059 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
5060}
5061
5062void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01005063 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005064 Location source = move->GetSource();
5065 Location destination = move->GetDestination();
5066
5067 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005068 DCHECK_NE(source.AsRegister<Register>(), IP);
5069 DCHECK_NE(destination.AsRegister<Register>(), IP);
5070 __ Mov(IP, source.AsRegister<Register>());
5071 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
5072 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005073 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005074 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005075 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005076 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005077 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
5078 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005079 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005080 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005081 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005082 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005083 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005084 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005085 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005086 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005087 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
5088 destination.AsRegisterPairHigh<Register>(),
5089 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005090 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005091 Register low_reg = source.IsRegisterPair()
5092 ? source.AsRegisterPairLow<Register>()
5093 : destination.AsRegisterPairLow<Register>();
5094 int mem = source.IsRegisterPair()
5095 ? destination.GetStackIndex()
5096 : source.GetStackIndex();
5097 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005098 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005099 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005100 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005101 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005102 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
5103 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005104 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005105 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005106 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005107 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
5108 DRegister reg = source.IsFpuRegisterPair()
5109 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
5110 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
5111 int mem = source.IsFpuRegisterPair()
5112 ? destination.GetStackIndex()
5113 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005114 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005115 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00005116 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005117 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
5118 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
5119 : destination.AsFpuRegister<SRegister>();
5120 int mem = source.IsFpuRegister()
5121 ? destination.GetStackIndex()
5122 : source.GetStackIndex();
5123
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005124 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00005125 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00005126 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005127 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005128 Exchange(source.GetStackIndex(), destination.GetStackIndex());
5129 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005130 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00005131 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005132 }
5133}
5134
5135void ParallelMoveResolverARM::SpillScratch(int reg) {
5136 __ Push(static_cast<Register>(reg));
5137}
5138
5139void ParallelMoveResolverARM::RestoreScratch(int reg) {
5140 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005141}
5142
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005143void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005144 InvokeRuntimeCallingConvention calling_convention;
5145 CodeGenerator::CreateLoadClassLocationSummary(
5146 cls,
5147 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Roland Levillain3b359c72015-11-17 19:35:12 +00005148 Location::RegisterLocation(R0),
5149 /* code_generator_supports_read_barrier */ true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005150}
5151
5152void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005153 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005154 if (cls->NeedsAccessCheck()) {
5155 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5156 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5157 cls,
5158 cls->GetDexPc(),
5159 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005160 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Calin Juravle580b6092015-10-06 17:35:58 +01005161 return;
5162 }
5163
Roland Levillain3b359c72015-11-17 19:35:12 +00005164 Location out_loc = locations->Out();
5165 Register out = out_loc.AsRegister<Register>();
Calin Juravle580b6092015-10-06 17:35:58 +01005166 Register current_method = locations->InAt(0).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005167
Calin Juravle580b6092015-10-06 17:35:58 +01005168 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005169 DCHECK(!cls->CanCallRuntime());
5170 DCHECK(!cls->MustGenerateClinitCheck());
Roland Levillainc9285912015-12-18 10:38:42 +00005171 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5172 GenerateGcRootFieldLoad(
5173 cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005174 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00005175 // /* GcRoot<mirror::Class>[] */ out =
5176 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005177 __ LoadFromOffset(kLoadWord,
5178 out,
5179 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01005180 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Roland Levillainc9285912015-12-18 10:38:42 +00005181 // /* GcRoot<mirror::Class> */ out = out[type_index]
5182 GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005183
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005184 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
5185 DCHECK(cls->CanCallRuntime());
5186 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
5187 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5188 codegen_->AddSlowPath(slow_path);
5189 if (!cls->IsInDexCache()) {
5190 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5191 }
5192 if (cls->MustGenerateClinitCheck()) {
5193 GenerateClassInitializationCheck(slow_path, out);
5194 } else {
5195 __ Bind(slow_path->GetExitLabel());
5196 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005197 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005198 }
5199}
5200
5201void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
5202 LocationSummary* locations =
5203 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5204 locations->SetInAt(0, Location::RequiresRegister());
5205 if (check->HasUses()) {
5206 locations->SetOut(Location::SameAsFirstInput());
5207 }
5208}
5209
5210void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005211 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005212 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005213 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005214 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005215 GenerateClassInitializationCheck(slow_path,
5216 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005217}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005218
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005219void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005220 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005221 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
5222 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
5223 __ b(slow_path->GetEntryLabel(), LT);
5224 // Even if the initialized flag is set, we may be in a situation where caches are not synced
5225 // properly. Therefore, we do a memory fence.
5226 __ dmb(ISH);
5227 __ Bind(slow_path->GetExitLabel());
5228}
5229
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005230HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
5231 HLoadString::LoadKind desired_string_load_kind) {
5232 if (kEmitCompilerReadBarrier) {
5233 switch (desired_string_load_kind) {
5234 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5235 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5236 case HLoadString::LoadKind::kBootImageAddress:
5237 // TODO: Implement for read barrier.
5238 return HLoadString::LoadKind::kDexCacheViaMethod;
5239 default:
5240 break;
5241 }
5242 }
5243 switch (desired_string_load_kind) {
5244 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5245 DCHECK(!GetCompilerOptions().GetCompilePic());
5246 break;
5247 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5248 DCHECK(GetCompilerOptions().GetCompilePic());
5249 break;
5250 case HLoadString::LoadKind::kBootImageAddress:
5251 break;
5252 case HLoadString::LoadKind::kDexCacheAddress:
5253 DCHECK(Runtime::Current()->UseJit());
5254 break;
5255 case HLoadString::LoadKind::kDexCachePcRelative:
5256 DCHECK(!Runtime::Current()->UseJit());
5257 // We disable pc-relative load when there is an irreducible loop, as the optimization
5258 // is incompatible with it.
5259 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
5260 // with irreducible loops.
5261 if (GetGraph()->HasIrreducibleLoops()) {
5262 return HLoadString::LoadKind::kDexCacheViaMethod;
5263 }
5264 break;
5265 case HLoadString::LoadKind::kDexCacheViaMethod:
5266 break;
5267 }
5268 return desired_string_load_kind;
5269}
5270
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005271void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005272 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005273 ? LocationSummary::kCallOnSlowPath
5274 : LocationSummary::kNoCall;
5275 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005276 HLoadString::LoadKind load_kind = load->GetLoadKind();
5277 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
5278 load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
5279 locations->SetInAt(0, Location::RequiresRegister());
5280 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005281 locations->SetOut(Location::RequiresRegister());
5282}
5283
5284void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005285 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005286 Location out_loc = locations->Out();
5287 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005288
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005289 switch (load->GetLoadKind()) {
5290 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
5291 DCHECK(!kEmitCompilerReadBarrier);
5292 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5293 load->GetStringIndex()));
5294 return; // No dex cache slow path.
5295 }
5296 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5297 DCHECK(!kEmitCompilerReadBarrier);
5298 CodeGeneratorARM::PcRelativePatchInfo* labels =
5299 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5300 __ BindTrackedLabel(&labels->movw_label);
5301 __ movw(out, /* placeholder */ 0u);
5302 __ BindTrackedLabel(&labels->movt_label);
5303 __ movt(out, /* placeholder */ 0u);
5304 __ BindTrackedLabel(&labels->add_pc_label);
5305 __ add(out, out, ShifterOperand(PC));
5306 return; // No dex cache slow path.
5307 }
5308 case HLoadString::LoadKind::kBootImageAddress: {
5309 DCHECK(!kEmitCompilerReadBarrier);
5310 DCHECK_NE(load->GetAddress(), 0u);
5311 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5312 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
5313 return; // No dex cache slow path.
5314 }
5315 case HLoadString::LoadKind::kDexCacheAddress: {
5316 DCHECK_NE(load->GetAddress(), 0u);
5317 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
5318 // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
5319 // a 128B range. To try and reduce the number of literals if we load multiple strings,
5320 // simply split the dex cache address to a 128B aligned base loaded from a literal
5321 // and the remaining offset embedded in the load.
5322 static_assert(sizeof(GcRoot<mirror::String>) == 4u, "Expected GC root to be 4 bytes.");
5323 DCHECK_ALIGNED(load->GetAddress(), 4u);
5324 constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
5325 uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
5326 uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
5327 __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
5328 GenerateGcRootFieldLoad(load, out_loc, out, offset);
5329 break;
5330 }
5331 case HLoadString::LoadKind::kDexCachePcRelative: {
5332 Register base_reg = locations->InAt(0).AsRegister<Register>();
5333 HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase();
5334 int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset();
5335 GenerateGcRootFieldLoad(load, out_loc, base_reg, offset);
5336 break;
5337 }
5338 case HLoadString::LoadKind::kDexCacheViaMethod: {
5339 Register current_method = locations->InAt(0).AsRegister<Register>();
5340
5341 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5342 GenerateGcRootFieldLoad(
5343 load, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
5344 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_
5345 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
5346 // /* GcRoot<mirror::String> */ out = out[string_index]
5347 GenerateGcRootFieldLoad(
5348 load, out_loc, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
5349 break;
5350 }
5351 default:
5352 LOG(FATAL) << "Unexpected load kind: " << load->GetLoadKind();
5353 UNREACHABLE();
5354 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005355
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005356 if (!load->IsInDexCache()) {
5357 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
5358 codegen_->AddSlowPath(slow_path);
5359 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
5360 __ Bind(slow_path->GetExitLabel());
5361 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005362}
5363
David Brazdilcb1c0552015-08-04 16:22:25 +01005364static int32_t GetExceptionTlsOffset() {
5365 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
5366}
5367
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005368void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
5369 LocationSummary* locations =
5370 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5371 locations->SetOut(Location::RequiresRegister());
5372}
5373
5374void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005375 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01005376 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5377}
5378
5379void LocationsBuilderARM::VisitClearException(HClearException* clear) {
5380 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5381}
5382
5383void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005384 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01005385 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005386}
5387
5388void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
5389 LocationSummary* locations =
5390 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5391 InvokeRuntimeCallingConvention calling_convention;
5392 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5393}
5394
5395void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
5396 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005397 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005398 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005399}
5400
Roland Levillainc9285912015-12-18 10:38:42 +00005401static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
5402 return kEmitCompilerReadBarrier &&
5403 (kUseBakerReadBarrier ||
5404 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5405 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5406 type_check_kind == TypeCheckKind::kArrayObjectCheck);
5407}
5408
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005409void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005410 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00005411 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5412 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005413 case TypeCheckKind::kExactCheck:
5414 case TypeCheckKind::kAbstractClassCheck:
5415 case TypeCheckKind::kClassHierarchyCheck:
5416 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005417 call_kind =
5418 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005419 break;
5420 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005421 case TypeCheckKind::kUnresolvedCheck:
5422 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005423 call_kind = LocationSummary::kCallOnSlowPath;
5424 break;
5425 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005426
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005427 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Roland Levillain3b359c72015-11-17 19:35:12 +00005428 locations->SetInAt(0, Location::RequiresRegister());
5429 locations->SetInAt(1, Location::RequiresRegister());
5430 // The "out" register is used as a temporary, so it overlaps with the inputs.
5431 // Note that TypeCheckSlowPathARM uses this register too.
5432 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5433 // When read barriers are enabled, we need a temporary register for
5434 // some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005435 if (TypeCheckNeedsATemporary(type_check_kind)) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005436 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005437 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005438}
5439
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005440void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005441 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005442 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005443 Location obj_loc = locations->InAt(0);
5444 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005445 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005446 Location out_loc = locations->Out();
5447 Register out = out_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005448 Location maybe_temp_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005449 locations->GetTemp(0) :
5450 Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005451 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005452 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5453 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5454 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005455 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07005456 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005457
5458 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005459 // avoid null check if we know obj is not null.
5460 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00005461 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005462 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005463
Roland Levillain3b359c72015-11-17 19:35:12 +00005464 // /* HeapReference<Class> */ out = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005465 GenerateReferenceLoadTwoRegisters(instruction, out_loc, obj_loc, class_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005466
Roland Levillainc9285912015-12-18 10:38:42 +00005467 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005468 case TypeCheckKind::kExactCheck: {
5469 __ cmp(out, ShifterOperand(cls));
5470 // Classes must be equal for the instanceof to succeed.
5471 __ b(&zero, NE);
5472 __ LoadImmediate(out, 1);
5473 __ b(&done);
5474 break;
5475 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005476
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005477 case TypeCheckKind::kAbstractClassCheck: {
5478 // If the class is abstract, we eagerly fetch the super class of the
5479 // object to avoid doing a comparison we know will fail.
5480 Label loop;
5481 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005482 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005483 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005484 // If `out` is null, we use it for the result, and jump to `done`.
5485 __ CompareAndBranchIfZero(out, &done);
5486 __ cmp(out, ShifterOperand(cls));
5487 __ b(&loop, NE);
5488 __ LoadImmediate(out, 1);
5489 if (zero.IsLinked()) {
5490 __ b(&done);
5491 }
5492 break;
5493 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005494
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005495 case TypeCheckKind::kClassHierarchyCheck: {
5496 // Walk over the class hierarchy to find a match.
5497 Label loop, success;
5498 __ Bind(&loop);
5499 __ cmp(out, ShifterOperand(cls));
5500 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005501 // /* HeapReference<Class> */ out = out->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005502 GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005503 __ CompareAndBranchIfNonZero(out, &loop);
5504 // If `out` is null, we use it for the result, and jump to `done`.
5505 __ b(&done);
5506 __ Bind(&success);
5507 __ LoadImmediate(out, 1);
5508 if (zero.IsLinked()) {
5509 __ b(&done);
5510 }
5511 break;
5512 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005513
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005514 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005515 // Do an exact check.
5516 Label exact_check;
5517 __ cmp(out, ShifterOperand(cls));
5518 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005519 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005520 // /* HeapReference<Class> */ out = out->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005521 GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005522 // If `out` is null, we use it for the result, and jump to `done`.
5523 __ CompareAndBranchIfZero(out, &done);
5524 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
5525 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5526 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005527 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005528 __ LoadImmediate(out, 1);
5529 __ b(&done);
5530 break;
5531 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005532
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005533 case TypeCheckKind::kArrayCheck: {
5534 __ cmp(out, ShifterOperand(cls));
5535 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00005536 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5537 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005538 codegen_->AddSlowPath(slow_path);
5539 __ b(slow_path->GetEntryLabel(), NE);
5540 __ LoadImmediate(out, 1);
5541 if (zero.IsLinked()) {
5542 __ b(&done);
5543 }
5544 break;
5545 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005546
Calin Juravle98893e12015-10-02 21:05:03 +01005547 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005548 case TypeCheckKind::kInterfaceCheck: {
5549 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005550 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00005551 // cases.
5552 //
5553 // We cannot directly call the InstanceofNonTrivial runtime
5554 // entry point without resorting to a type checking slow path
5555 // here (i.e. by calling InvokeRuntime directly), as it would
5556 // require to assign fixed registers for the inputs of this
5557 // HInstanceOf instruction (following the runtime calling
5558 // convention), which might be cluttered by the potential first
5559 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005560 //
5561 // TODO: Introduce a new runtime entry point taking the object
5562 // to test (instead of its class) as argument, and let it deal
5563 // with the read barrier issues. This will let us refactor this
5564 // case of the `switch` code as it was previously (with a direct
5565 // call to the runtime not using a type checking slow path).
5566 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005567 DCHECK(locations->OnlyCallsOnSlowPath());
5568 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5569 /* is_fatal */ false);
5570 codegen_->AddSlowPath(slow_path);
5571 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005572 if (zero.IsLinked()) {
5573 __ b(&done);
5574 }
5575 break;
5576 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005577 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005578
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005579 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005580 __ Bind(&zero);
5581 __ LoadImmediate(out, 0);
5582 }
5583
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005584 if (done.IsLinked()) {
5585 __ Bind(&done);
5586 }
5587
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005588 if (slow_path != nullptr) {
5589 __ Bind(slow_path->GetExitLabel());
5590 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005591}
5592
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005593void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005594 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5595 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5596
Roland Levillain3b359c72015-11-17 19:35:12 +00005597 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
5598 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005599 case TypeCheckKind::kExactCheck:
5600 case TypeCheckKind::kAbstractClassCheck:
5601 case TypeCheckKind::kClassHierarchyCheck:
5602 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005603 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
5604 LocationSummary::kCallOnSlowPath :
5605 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005606 break;
5607 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00005608 case TypeCheckKind::kUnresolvedCheck:
5609 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005610 call_kind = LocationSummary::kCallOnSlowPath;
5611 break;
5612 }
5613
Roland Levillain3b359c72015-11-17 19:35:12 +00005614 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5615 locations->SetInAt(0, Location::RequiresRegister());
5616 locations->SetInAt(1, Location::RequiresRegister());
5617 // Note that TypeCheckSlowPathARM uses this "temp" register too.
5618 locations->AddTemp(Location::RequiresRegister());
5619 // When read barriers are enabled, we need an additional temporary
5620 // register for some cases.
Roland Levillainc9285912015-12-18 10:38:42 +00005621 if (TypeCheckNeedsATemporary(type_check_kind)) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005622 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005623 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005624}
5625
5626void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00005627 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005628 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005629 Location obj_loc = locations->InAt(0);
5630 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005631 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00005632 Location temp_loc = locations->GetTemp(0);
5633 Register temp = temp_loc.AsRegister<Register>();
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005634 Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ?
Roland Levillainc9285912015-12-18 10:38:42 +00005635 locations->GetTemp(1) :
5636 Location::NoLocation();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005637 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005638 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5639 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5640 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005641
Roland Levillain3b359c72015-11-17 19:35:12 +00005642 bool is_type_check_slow_path_fatal =
5643 (type_check_kind == TypeCheckKind::kExactCheck ||
5644 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
5645 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
5646 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
5647 !instruction->CanThrowIntoCatchBlock();
5648 SlowPathCode* type_check_slow_path =
5649 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
5650 is_type_check_slow_path_fatal);
5651 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005652
5653 Label done;
5654 // Avoid null check if we know obj is not null.
5655 if (instruction->MustDoNullCheck()) {
5656 __ CompareAndBranchIfZero(obj, &done);
5657 }
5658
Roland Levillain3b359c72015-11-17 19:35:12 +00005659 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005660 GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005661
Roland Levillain3b359c72015-11-17 19:35:12 +00005662 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005663 case TypeCheckKind::kExactCheck:
5664 case TypeCheckKind::kArrayCheck: {
5665 __ cmp(temp, ShifterOperand(cls));
5666 // Jump to slow path for throwing the exception or doing a
5667 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005668 __ b(type_check_slow_path->GetEntryLabel(), NE);
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::kAbstractClassCheck: {
5673 // If the class is abstract, we eagerly fetch the super class of the
5674 // object to avoid doing a comparison we know will fail.
Roland Levillain3b359c72015-11-17 19:35:12 +00005675 Label loop, compare_classes;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005676 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005677 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005678 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005679
5680 // If the class reference currently in `temp` is not null, jump
5681 // to the `compare_classes` label to compare it with the checked
5682 // class.
5683 __ CompareAndBranchIfNonZero(temp, &compare_classes);
5684 // Otherwise, jump to the slow path to throw the exception.
5685 //
5686 // But before, move back the object's class into `temp` before
5687 // going into the slow path, as it has been overwritten in the
5688 // meantime.
5689 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005690 GenerateReferenceLoadTwoRegisters(
5691 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005692 __ b(type_check_slow_path->GetEntryLabel());
5693
5694 __ Bind(&compare_classes);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005695 __ cmp(temp, ShifterOperand(cls));
5696 __ b(&loop, NE);
5697 break;
5698 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005699
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005700 case TypeCheckKind::kClassHierarchyCheck: {
5701 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005702 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005703 __ Bind(&loop);
5704 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005705 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005706
Roland Levillain3b359c72015-11-17 19:35:12 +00005707 // /* HeapReference<Class> */ temp = temp->super_class_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005708 GenerateReferenceLoadOneRegister(instruction, temp_loc, super_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005709
5710 // If the class reference currently in `temp` is not null, jump
5711 // back at the beginning of the loop.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005712 __ CompareAndBranchIfNonZero(temp, &loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00005713 // Otherwise, jump to the slow path to throw the exception.
5714 //
5715 // But before, move back the object's class into `temp` before
5716 // going into the slow path, as it has been overwritten in the
5717 // meantime.
5718 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005719 GenerateReferenceLoadTwoRegisters(
5720 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005721 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005722 break;
5723 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005724
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005725 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005726 // Do an exact check.
Roland Levillain3b359c72015-11-17 19:35:12 +00005727 Label check_non_primitive_component_type;
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005728 __ cmp(temp, ShifterOperand(cls));
5729 __ b(&done, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00005730
5731 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00005732 // /* HeapReference<Class> */ temp = temp->component_type_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005733 GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005734
5735 // If the component type is not null (i.e. the object is indeed
5736 // an array), jump to label `check_non_primitive_component_type`
5737 // to further check that this component type is not a primitive
5738 // type.
5739 __ CompareAndBranchIfNonZero(temp, &check_non_primitive_component_type);
5740 // Otherwise, jump to the slow path to throw the exception.
5741 //
5742 // But before, move back the object's class into `temp` before
5743 // going into the slow path, as it has been overwritten in the
5744 // meantime.
5745 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005746 GenerateReferenceLoadTwoRegisters(
5747 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005748 __ b(type_check_slow_path->GetEntryLabel());
5749
5750 __ Bind(&check_non_primitive_component_type);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005751 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00005752 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
5753 __ CompareAndBranchIfZero(temp, &done);
5754 // Same comment as above regarding `temp` and the slow path.
5755 // /* HeapReference<Class> */ temp = obj->klass_
Roland Levillain95e7ffc2016-01-22 11:57:25 +00005756 GenerateReferenceLoadTwoRegisters(
5757 instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
Roland Levillain3b359c72015-11-17 19:35:12 +00005758 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005759 break;
5760 }
Roland Levillain3b359c72015-11-17 19:35:12 +00005761
Calin Juravle98893e12015-10-02 21:05:03 +01005762 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005763 case TypeCheckKind::kInterfaceCheck:
Roland Levillaine3f43ac2016-01-19 15:07:47 +00005764 // We always go into the type check slow path for the unresolved
5765 // and interface check cases.
Roland Levillain3b359c72015-11-17 19:35:12 +00005766 //
5767 // We cannot directly call the CheckCast runtime entry point
5768 // without resorting to a type checking slow path here (i.e. by
5769 // calling InvokeRuntime directly), as it would require to
5770 // assign fixed registers for the inputs of this HInstanceOf
5771 // instruction (following the runtime calling convention), which
5772 // might be cluttered by the potential first read barrier
5773 // emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00005774 //
5775 // TODO: Introduce a new runtime entry point taking the object
5776 // to test (instead of its class) as argument, and let it deal
5777 // with the read barrier issues. This will let us refactor this
5778 // case of the `switch` code as it was previously (with a direct
5779 // call to the runtime not using a type checking slow path).
5780 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00005781 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005782 break;
5783 }
5784 __ Bind(&done);
5785
Roland Levillain3b359c72015-11-17 19:35:12 +00005786 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005787}
5788
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005789void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5790 LocationSummary* locations =
5791 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5792 InvokeRuntimeCallingConvention calling_convention;
5793 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5794}
5795
5796void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5797 codegen_->InvokeRuntime(instruction->IsEnter()
5798 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5799 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005800 instruction->GetDexPc(),
5801 nullptr);
Roland Levillain888d0672015-11-23 18:53:50 +00005802 if (instruction->IsEnter()) {
5803 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5804 } else {
5805 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5806 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005807}
5808
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005809void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5810void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5811void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005812
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005813void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005814 LocationSummary* locations =
5815 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5816 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5817 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005818 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005819 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005820 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005821 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005822}
5823
5824void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5825 HandleBitwiseOperation(instruction);
5826}
5827
5828void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5829 HandleBitwiseOperation(instruction);
5830}
5831
5832void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5833 HandleBitwiseOperation(instruction);
5834}
5835
Artem Serov7fc63502016-02-09 17:15:29 +00005836
5837void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5838 LocationSummary* locations =
5839 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5840 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5841 || instruction->GetResultType() == Primitive::kPrimLong);
5842
5843 locations->SetInAt(0, Location::RequiresRegister());
5844 locations->SetInAt(1, Location::RequiresRegister());
5845 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5846}
5847
5848void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
5849 LocationSummary* locations = instruction->GetLocations();
5850 Location first = locations->InAt(0);
5851 Location second = locations->InAt(1);
5852 Location out = locations->Out();
5853
5854 if (instruction->GetResultType() == Primitive::kPrimInt) {
5855 Register first_reg = first.AsRegister<Register>();
5856 ShifterOperand second_reg(second.AsRegister<Register>());
5857 Register out_reg = out.AsRegister<Register>();
5858
5859 switch (instruction->GetOpKind()) {
5860 case HInstruction::kAnd:
5861 __ bic(out_reg, first_reg, second_reg);
5862 break;
5863 case HInstruction::kOr:
5864 __ orn(out_reg, first_reg, second_reg);
5865 break;
5866 // There is no EON on arm.
5867 case HInstruction::kXor:
5868 default:
5869 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5870 UNREACHABLE();
5871 }
5872 return;
5873
5874 } else {
5875 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5876 Register first_low = first.AsRegisterPairLow<Register>();
5877 Register first_high = first.AsRegisterPairHigh<Register>();
5878 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5879 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5880 Register out_low = out.AsRegisterPairLow<Register>();
5881 Register out_high = out.AsRegisterPairHigh<Register>();
5882
5883 switch (instruction->GetOpKind()) {
5884 case HInstruction::kAnd:
5885 __ bic(out_low, first_low, second_low);
5886 __ bic(out_high, first_high, second_high);
5887 break;
5888 case HInstruction::kOr:
5889 __ orn(out_low, first_low, second_low);
5890 __ orn(out_high, first_high, second_high);
5891 break;
5892 // There is no EON on arm.
5893 case HInstruction::kXor:
5894 default:
5895 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
5896 UNREACHABLE();
5897 }
5898 }
5899}
5900
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005901void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5902 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5903 if (value == 0xffffffffu) {
5904 if (out != first) {
5905 __ mov(out, ShifterOperand(first));
5906 }
5907 return;
5908 }
5909 if (value == 0u) {
5910 __ mov(out, ShifterOperand(0));
5911 return;
5912 }
5913 ShifterOperand so;
5914 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5915 __ and_(out, first, so);
5916 } else {
5917 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5918 __ bic(out, first, ShifterOperand(~value));
5919 }
5920}
5921
5922void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5923 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5924 if (value == 0u) {
5925 if (out != first) {
5926 __ mov(out, ShifterOperand(first));
5927 }
5928 return;
5929 }
5930 if (value == 0xffffffffu) {
5931 __ mvn(out, ShifterOperand(0));
5932 return;
5933 }
5934 ShifterOperand so;
5935 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5936 __ orr(out, first, so);
5937 } else {
5938 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5939 __ orn(out, first, ShifterOperand(~value));
5940 }
5941}
5942
5943void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5944 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5945 if (value == 0u) {
5946 if (out != first) {
5947 __ mov(out, ShifterOperand(first));
5948 }
5949 return;
5950 }
5951 __ eor(out, first, ShifterOperand(value));
5952}
5953
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005954void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5955 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005956 Location first = locations->InAt(0);
5957 Location second = locations->InAt(1);
5958 Location out = locations->Out();
5959
5960 if (second.IsConstant()) {
5961 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5962 uint32_t value_low = Low32Bits(value);
5963 if (instruction->GetResultType() == Primitive::kPrimInt) {
5964 Register first_reg = first.AsRegister<Register>();
5965 Register out_reg = out.AsRegister<Register>();
5966 if (instruction->IsAnd()) {
5967 GenerateAndConst(out_reg, first_reg, value_low);
5968 } else if (instruction->IsOr()) {
5969 GenerateOrrConst(out_reg, first_reg, value_low);
5970 } else {
5971 DCHECK(instruction->IsXor());
5972 GenerateEorConst(out_reg, first_reg, value_low);
5973 }
5974 } else {
5975 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5976 uint32_t value_high = High32Bits(value);
5977 Register first_low = first.AsRegisterPairLow<Register>();
5978 Register first_high = first.AsRegisterPairHigh<Register>();
5979 Register out_low = out.AsRegisterPairLow<Register>();
5980 Register out_high = out.AsRegisterPairHigh<Register>();
5981 if (instruction->IsAnd()) {
5982 GenerateAndConst(out_low, first_low, value_low);
5983 GenerateAndConst(out_high, first_high, value_high);
5984 } else if (instruction->IsOr()) {
5985 GenerateOrrConst(out_low, first_low, value_low);
5986 GenerateOrrConst(out_high, first_high, value_high);
5987 } else {
5988 DCHECK(instruction->IsXor());
5989 GenerateEorConst(out_low, first_low, value_low);
5990 GenerateEorConst(out_high, first_high, value_high);
5991 }
5992 }
5993 return;
5994 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005995
5996 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005997 Register first_reg = first.AsRegister<Register>();
5998 ShifterOperand second_reg(second.AsRegister<Register>());
5999 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006000 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006001 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006002 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006003 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006004 } else {
6005 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006006 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006007 }
6008 } else {
6009 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006010 Register first_low = first.AsRegisterPairLow<Register>();
6011 Register first_high = first.AsRegisterPairHigh<Register>();
6012 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
6013 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
6014 Register out_low = out.AsRegisterPairLow<Register>();
6015 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006016 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006017 __ and_(out_low, first_low, second_low);
6018 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006019 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006020 __ orr(out_low, first_low, second_low);
6021 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006022 } else {
6023 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01006024 __ eor(out_low, first_low, second_low);
6025 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00006026 }
6027 }
6028}
6029
Roland Levillainc9285912015-12-18 10:38:42 +00006030void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(HInstruction* instruction,
6031 Location out,
6032 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006033 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006034 Register out_reg = out.AsRegister<Register>();
6035 if (kEmitCompilerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006036 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006037 if (kUseBakerReadBarrier) {
6038 // Load with fast path based Baker's read barrier.
6039 // /* HeapReference<Object> */ out = *(out + offset)
6040 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006041 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006042 } else {
6043 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006044 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00006045 // in the following move operation, as we will need it for the
6046 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006047 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00006048 // /* HeapReference<Object> */ out = *(out + offset)
6049 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006050 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00006051 }
6052 } else {
6053 // Plain load with no read barrier.
6054 // /* HeapReference<Object> */ out = *(out + offset)
6055 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6056 __ MaybeUnpoisonHeapReference(out_reg);
6057 }
6058}
6059
6060void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
6061 Location out,
6062 Location obj,
6063 uint32_t offset,
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006064 Location maybe_temp) {
Roland Levillainc9285912015-12-18 10:38:42 +00006065 Register out_reg = out.AsRegister<Register>();
6066 Register obj_reg = obj.AsRegister<Register>();
6067 if (kEmitCompilerReadBarrier) {
6068 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006069 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00006070 // Load with fast path based Baker's read barrier.
6071 // /* HeapReference<Object> */ out = *(obj + offset)
6072 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00006073 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00006074 } else {
6075 // Load with slow path based read barrier.
6076 // /* HeapReference<Object> */ out = *(obj + offset)
6077 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6078 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6079 }
6080 } else {
6081 // Plain load with no read barrier.
6082 // /* HeapReference<Object> */ out = *(obj + offset)
6083 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6084 __ MaybeUnpoisonHeapReference(out_reg);
6085 }
6086}
6087
6088void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
6089 Location root,
6090 Register obj,
6091 uint32_t offset) {
6092 Register root_reg = root.AsRegister<Register>();
6093 if (kEmitCompilerReadBarrier) {
6094 if (kUseBakerReadBarrier) {
6095 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6096 // Baker's read barrier are used:
6097 //
6098 // root = obj.field;
6099 // if (Thread::Current()->GetIsGcMarking()) {
6100 // root = ReadBarrier::Mark(root)
6101 // }
6102
6103 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6104 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6105 static_assert(
6106 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6107 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6108 "have different sizes.");
6109 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6110 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6111 "have different sizes.");
6112
6113 // Slow path used to mark the GC root `root`.
6114 SlowPathCode* slow_path =
6115 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
6116 codegen_->AddSlowPath(slow_path);
6117
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006118 // IP = Thread::Current()->GetIsGcMarking()
Roland Levillainc9285912015-12-18 10:38:42 +00006119 __ LoadFromOffset(
6120 kLoadWord, IP, TR, Thread::IsGcMarkingOffset<kArmWordSize>().Int32Value());
6121 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
6122 __ Bind(slow_path->GetExitLabel());
6123 } else {
6124 // GC root loaded through a slow path for read barriers other
6125 // than Baker's.
6126 // /* GcRoot<mirror::Object>* */ root = obj + offset
6127 __ AddConstant(root_reg, obj, offset);
6128 // /* mirror::Object* */ root = root->Read()
6129 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6130 }
6131 } else {
6132 // Plain GC root load with no read barrier.
6133 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6134 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6135 // Note that GC roots are not affected by heap poisoning, thus we
6136 // do not have to unpoison `root_reg` here.
6137 }
6138}
6139
6140void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6141 Location ref,
6142 Register obj,
6143 uint32_t offset,
6144 Location temp,
6145 bool needs_null_check) {
6146 DCHECK(kEmitCompilerReadBarrier);
6147 DCHECK(kUseBakerReadBarrier);
6148
6149 // /* HeapReference<Object> */ ref = *(obj + offset)
6150 Location no_index = Location::NoLocation();
6151 GenerateReferenceLoadWithBakerReadBarrier(
6152 instruction, ref, obj, offset, no_index, temp, needs_null_check);
6153}
6154
6155void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6156 Location ref,
6157 Register obj,
6158 uint32_t data_offset,
6159 Location index,
6160 Location temp,
6161 bool needs_null_check) {
6162 DCHECK(kEmitCompilerReadBarrier);
6163 DCHECK(kUseBakerReadBarrier);
6164
6165 // /* HeapReference<Object> */ ref =
6166 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
6167 GenerateReferenceLoadWithBakerReadBarrier(
6168 instruction, ref, obj, data_offset, index, temp, needs_null_check);
6169}
6170
6171void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
6172 Location ref,
6173 Register obj,
6174 uint32_t offset,
6175 Location index,
6176 Location temp,
6177 bool needs_null_check) {
6178 DCHECK(kEmitCompilerReadBarrier);
6179 DCHECK(kUseBakerReadBarrier);
6180
6181 // In slow path based read barriers, the read barrier call is
6182 // inserted after the original load. However, in fast path based
6183 // Baker's read barriers, we need to perform the load of
6184 // mirror::Object::monitor_ *before* the original reference load.
6185 // This load-load ordering is required by the read barrier.
6186 // The fast path/slow path (for Baker's algorithm) should look like:
6187 //
6188 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
6189 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
6190 // HeapReference<Object> ref = *src; // Original reference load.
6191 // bool is_gray = (rb_state == ReadBarrier::gray_ptr_);
6192 // if (is_gray) {
6193 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
6194 // }
6195 //
6196 // Note: the original implementation in ReadBarrier::Barrier is
Roland Levillaine3f43ac2016-01-19 15:07:47 +00006197 // slightly more complex as it performs additional checks that we do
6198 // not do here for performance reasons.
Roland Levillainc9285912015-12-18 10:38:42 +00006199
6200 Register ref_reg = ref.AsRegister<Register>();
6201 Register temp_reg = temp.AsRegister<Register>();
6202 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
6203
6204 // /* int32_t */ monitor = obj->monitor_
6205 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
6206 if (needs_null_check) {
6207 MaybeRecordImplicitNullCheck(instruction);
6208 }
6209 // /* LockWord */ lock_word = LockWord(monitor)
6210 static_assert(sizeof(LockWord) == sizeof(int32_t),
6211 "art::LockWord and int32_t have different sizes.");
6212 // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
6213 __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
6214 __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6215 static_assert(
6216 LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
6217 "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
6218
6219 // Introduce a dependency on the high bits of rb_state, which shall
6220 // be all zeroes, to prevent load-load reordering, and without using
6221 // a memory barrier (which would be more expensive).
6222 // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
6223 __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
6224 // obj is unchanged by this operation, but its value now depends on
6225 // IP, which depends on temp_reg.
6226 __ add(obj, obj, ShifterOperand(IP));
6227
6228 // The actual reference load.
6229 if (index.IsValid()) {
6230 static_assert(
6231 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6232 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
6233 // /* HeapReference<Object> */ ref =
6234 // *(obj + offset + index * sizeof(HeapReference<Object>))
6235 if (index.IsConstant()) {
6236 size_t computed_offset =
6237 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
6238 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
6239 } else {
6240 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
6241 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
6242 }
6243 } else {
6244 // /* HeapReference<Object> */ ref = *(obj + offset)
6245 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
6246 }
6247
6248 // Object* ref = ref_addr->AsMirrorPtr()
6249 __ MaybeUnpoisonHeapReference(ref_reg);
6250
6251 // Slow path used to mark the object `ref` when it is gray.
6252 SlowPathCode* slow_path =
6253 new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
6254 AddSlowPath(slow_path);
6255
6256 // if (rb_state == ReadBarrier::gray_ptr_)
6257 // ref = ReadBarrier::Mark(ref);
6258 __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
6259 __ b(slow_path->GetEntryLabel(), EQ);
6260 __ Bind(slow_path->GetExitLabel());
6261}
6262
6263void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
6264 Location out,
6265 Location ref,
6266 Location obj,
6267 uint32_t offset,
6268 Location index) {
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 reference load.
6272 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006273 // If heap poisoning is enabled, the unpoisoning of the loaded
6274 // reference will be carried out by the runtime within the slow
6275 // path.
6276 //
6277 // Note that `ref` currently does not get unpoisoned (when heap
6278 // poisoning is enabled), which is alright as the `ref` argument is
6279 // not used by the artReadBarrierSlow entry point.
6280 //
6281 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
6282 SlowPathCode* slow_path = new (GetGraph()->GetArena())
6283 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
6284 AddSlowPath(slow_path);
6285
Roland Levillain3b359c72015-11-17 19:35:12 +00006286 __ b(slow_path->GetEntryLabel());
6287 __ Bind(slow_path->GetExitLabel());
6288}
6289
Roland Levillainc9285912015-12-18 10:38:42 +00006290void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
6291 Location out,
6292 Location ref,
6293 Location obj,
6294 uint32_t offset,
6295 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006296 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00006297 // Baker's read barriers shall be handled by the fast path
6298 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
6299 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00006300 // If heap poisoning is enabled, unpoisoning will be taken care of
6301 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00006302 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00006303 } else if (kPoisonHeapReferences) {
6304 __ UnpoisonHeapReference(out.AsRegister<Register>());
6305 }
6306}
6307
Roland Levillainc9285912015-12-18 10:38:42 +00006308void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
6309 Location out,
6310 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006311 DCHECK(kEmitCompilerReadBarrier);
6312
Roland Levillainc9285912015-12-18 10:38:42 +00006313 // Insert a slow path based read barrier *after* the GC root load.
6314 //
Roland Levillain3b359c72015-11-17 19:35:12 +00006315 // Note that GC roots are not affected by heap poisoning, so we do
6316 // not need to do anything special for this here.
6317 SlowPathCode* slow_path =
6318 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
6319 AddSlowPath(slow_path);
6320
Roland Levillain3b359c72015-11-17 19:35:12 +00006321 __ b(slow_path->GetEntryLabel());
6322 __ Bind(slow_path->GetExitLabel());
6323}
6324
Vladimir Markodc151b22015-10-15 18:02:30 +01006325HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
6326 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
6327 MethodReference target_method) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006328 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
6329 // We disable pc-relative load when there is an irreducible loop, as the optimization
6330 // is incompatible with it.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006331 // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
6332 // with irreducible loops.
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006333 if (GetGraph()->HasIrreducibleLoops() &&
6334 (dispatch_info.method_load_kind ==
6335 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative)) {
6336 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
6337 }
6338
6339 if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
Vladimir Markodc151b22015-10-15 18:02:30 +01006340 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
6341 if (&outer_dex_file != target_method.dex_file) {
6342 // Calls across dex files are more likely to exceed the available BL range,
6343 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
6344 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
6345 (desired_dispatch_info.method_load_kind ==
6346 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
6347 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
6348 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
6349 return HInvokeStaticOrDirect::DispatchInfo {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006350 dispatch_info.method_load_kind,
Vladimir Markodc151b22015-10-15 18:02:30 +01006351 code_ptr_location,
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006352 dispatch_info.method_load_data,
Vladimir Markodc151b22015-10-15 18:02:30 +01006353 0u
6354 };
6355 }
6356 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00006357 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01006358}
6359
Vladimir Markob4536b72015-11-24 13:45:23 +00006360Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
6361 Register temp) {
6362 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
6363 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
6364 if (!invoke->GetLocations()->Intrinsified()) {
6365 return location.AsRegister<Register>();
6366 }
6367 // For intrinsics we allow any location, so it may be on the stack.
6368 if (!location.IsRegister()) {
6369 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
6370 return temp;
6371 }
6372 // For register locations, check if the register was saved. If so, get it from the stack.
6373 // Note: There is a chance that the register was saved but not overwritten, so we could
6374 // save one load. However, since this is just an intrinsic slow path we prefer this
6375 // simple and more robust approach rather that trying to determine if that's the case.
6376 SlowPathCode* slow_path = GetCurrentSlowPath();
6377 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
6378 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
6379 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
6380 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
6381 return temp;
6382 }
6383 return location.AsRegister<Register>();
6384}
6385
Nicolas Geoffray38207af2015-06-01 15:46:22 +01006386void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00006387 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00006388 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00006389 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6390 // LR = code address from literal pool with link-time patch.
6391 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00006392 break;
6393 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6394 // LR = invoke->GetDirectCodePtr();
6395 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00006396 break;
6397 default:
6398 break;
6399 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006400
Vladimir Marko58155012015-08-19 12:49:41 +00006401 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
6402 switch (invoke->GetMethodLoadKind()) {
6403 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
6404 // temp = thread->string_init_entrypoint
6405 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
6406 break;
6407 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00006408 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006409 break;
6410 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
6411 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
6412 break;
6413 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
6414 __ LoadLiteral(temp.AsRegister<Register>(),
6415 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
6416 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00006417 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
6418 HArmDexCacheArraysBase* base =
6419 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
6420 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
6421 temp.AsRegister<Register>());
6422 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
6423 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
6424 break;
6425 }
Vladimir Marko58155012015-08-19 12:49:41 +00006426 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00006427 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00006428 Register method_reg;
6429 Register reg = temp.AsRegister<Register>();
6430 if (current_method.IsRegister()) {
6431 method_reg = current_method.AsRegister<Register>();
6432 } else {
6433 DCHECK(invoke->GetLocations()->Intrinsified());
6434 DCHECK(!current_method.IsValid());
6435 method_reg = reg;
6436 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
6437 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006438 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
6439 __ LoadFromOffset(kLoadWord,
6440 reg,
6441 method_reg,
6442 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00006443 // temp = temp[index_in_cache]
6444 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
6445 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
6446 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01006447 }
Vladimir Marko58155012015-08-19 12:49:41 +00006448 }
6449
6450 switch (invoke->GetCodePtrLocation()) {
6451 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
6452 __ bl(GetFrameEntryLabel());
6453 break;
6454 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01006455 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006456 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01006457 // Arbitrarily branch to the BL itself, override at link time.
6458 __ bl(&relative_call_patches_.back().label);
6459 break;
Vladimir Marko58155012015-08-19 12:49:41 +00006460 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
6461 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
6462 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00006463 // LR()
6464 __ blx(LR);
6465 break;
6466 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
6467 // LR = callee_method->entry_point_from_quick_compiled_code_
6468 __ LoadFromOffset(
6469 kLoadWord, LR, callee_method.AsRegister<Register>(),
6470 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
6471 // LR()
6472 __ blx(LR);
6473 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006474 }
6475
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08006476 DCHECK(!IsLeafMethod());
6477}
6478
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006479void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
6480 Register temp = temp_location.AsRegister<Register>();
6481 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6482 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006483
6484 // Use the calling convention instead of the location of the receiver, as
6485 // intrinsics may have put the receiver in a different register. In the intrinsics
6486 // slow path, the arguments have been moved to the right place, so here we are
6487 // guaranteed that the receiver is the first register of the calling convention.
6488 InvokeDexCallingConvention calling_convention;
6489 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006490 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00006491 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00006492 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006493 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00006494 // Instead of simply (possibly) unpoisoning `temp` here, we should
6495 // emit a read barrier for the previous class reference load.
6496 // However this is not required in practice, as this is an
6497 // intermediate/temporary reference and because the current
6498 // concurrent copying collector keeps the from-space memory
6499 // intact/accessible until the end of the marking phase (the
6500 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00006501 __ MaybeUnpoisonHeapReference(temp);
6502 // temp = temp->GetMethodAt(method_offset);
6503 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
6504 kArmWordSize).Int32Value();
6505 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
6506 // LR = temp->GetEntryPoint();
6507 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
6508 // LR();
6509 __ blx(LR);
6510}
6511
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006512CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
6513 const DexFile& dex_file, uint32_t string_index) {
6514 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
6515}
6516
6517CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
6518 const DexFile& dex_file, uint32_t element_offset) {
6519 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
6520}
6521
6522CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
6523 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
6524 patches->emplace_back(dex_file, offset_or_index);
6525 return &patches->back();
6526}
6527
6528Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
6529 uint32_t string_index) {
6530 return boot_image_string_patches_.GetOrCreate(
6531 StringReference(&dex_file, string_index),
6532 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
6533}
6534
6535Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
6536 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
6537 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
6538 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
6539}
6540
6541Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
6542 return DeduplicateUint32Literal(address, &uint32_literals_);
6543}
6544
Vladimir Marko58155012015-08-19 12:49:41 +00006545void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
6546 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00006547 size_t size =
6548 method_patches_.size() +
6549 call_patches_.size() +
6550 relative_call_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006551 /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
6552 boot_image_string_patches_.size() +
6553 /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
6554 boot_image_address_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00006555 linker_patches->reserve(size);
6556 for (const auto& entry : method_patches_) {
6557 const MethodReference& target_method = entry.first;
6558 Literal* literal = entry.second;
6559 DCHECK(literal->GetLabel()->IsBound());
6560 uint32_t literal_offset = literal->GetLabel()->Position();
6561 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
6562 target_method.dex_file,
6563 target_method.dex_method_index));
6564 }
6565 for (const auto& entry : call_patches_) {
6566 const MethodReference& target_method = entry.first;
6567 Literal* literal = entry.second;
6568 DCHECK(literal->GetLabel()->IsBound());
6569 uint32_t literal_offset = literal->GetLabel()->Position();
6570 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
6571 target_method.dex_file,
6572 target_method.dex_method_index));
6573 }
6574 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
6575 uint32_t literal_offset = info.label.Position();
6576 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
6577 info.target_method.dex_file,
6578 info.target_method.dex_method_index));
6579 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006580 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
6581 const DexFile& dex_file = info.target_dex_file;
6582 size_t base_element_offset = info.offset_or_index;
6583 DCHECK(info.add_pc_label.IsBound());
6584 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006585 // Add MOVW patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006586 DCHECK(info.movw_label.IsBound());
6587 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006588 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
6589 &dex_file,
6590 add_pc_offset,
6591 base_element_offset));
6592 // Add MOVT patch.
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006593 DCHECK(info.movt_label.IsBound());
6594 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
Vladimir Markob4536b72015-11-24 13:45:23 +00006595 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
6596 &dex_file,
6597 add_pc_offset,
6598 base_element_offset));
6599 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006600 for (const auto& entry : boot_image_string_patches_) {
6601 const StringReference& target_string = entry.first;
6602 Literal* literal = entry.second;
6603 DCHECK(literal->GetLabel()->IsBound());
6604 uint32_t literal_offset = literal->GetLabel()->Position();
6605 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
6606 target_string.dex_file,
6607 target_string.string_index));
6608 }
6609 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
6610 const DexFile& dex_file = info.target_dex_file;
6611 uint32_t string_index = info.offset_or_index;
6612 DCHECK(info.add_pc_label.IsBound());
6613 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
6614 // Add MOVW patch.
6615 DCHECK(info.movw_label.IsBound());
6616 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
6617 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
6618 &dex_file,
6619 add_pc_offset,
6620 string_index));
6621 // Add MOVT patch.
6622 DCHECK(info.movt_label.IsBound());
6623 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
6624 linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
6625 &dex_file,
6626 add_pc_offset,
6627 string_index));
6628 }
6629 for (const auto& entry : boot_image_address_patches_) {
6630 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
6631 Literal* literal = entry.second;
6632 DCHECK(literal->GetLabel()->IsBound());
6633 uint32_t literal_offset = literal->GetLabel()->Position();
6634 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
6635 }
6636}
6637
6638Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
6639 return map->GetOrCreate(
6640 value,
6641 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00006642}
6643
6644Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
6645 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006646 return map->GetOrCreate(
6647 target_method,
6648 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00006649}
6650
6651Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
6652 return DeduplicateMethodLiteral(target_method, &method_patches_);
6653}
6654
6655Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
6656 return DeduplicateMethodLiteral(target_method, &call_patches_);
6657}
6658
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03006659void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6660 LocationSummary* locations =
6661 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
6662 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
6663 Location::RequiresRegister());
6664 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
6665 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
6666 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6667}
6668
6669void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
6670 LocationSummary* locations = instr->GetLocations();
6671 Register res = locations->Out().AsRegister<Register>();
6672 Register accumulator =
6673 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
6674 Register mul_left =
6675 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
6676 Register mul_right =
6677 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
6678
6679 if (instr->GetOpKind() == HInstruction::kAdd) {
6680 __ mla(res, mul_left, mul_right, accumulator);
6681 } else {
6682 __ mls(res, mul_left, mul_right, accumulator);
6683 }
6684}
6685
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006686void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006687 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006688 LOG(FATAL) << "Unreachable";
6689}
6690
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006691void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00006692 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00006693 LOG(FATAL) << "Unreachable";
6694}
6695
Mark Mendellfe57faa2015-09-18 09:26:15 -04006696// Simple implementation of packed switch - generate cascaded compare/jumps.
6697void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6698 LocationSummary* locations =
6699 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6700 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006701 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006702 codegen_->GetAssembler()->IsThumb()) {
6703 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
6704 if (switch_instr->GetStartValue() != 0) {
6705 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
6706 }
6707 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006708}
6709
6710void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6711 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006712 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04006713 LocationSummary* locations = switch_instr->GetLocations();
6714 Register value_reg = locations->InAt(0).AsRegister<Register>();
6715 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6716
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006717 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006718 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006719 Register temp_reg = IP;
6720 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
6721 // the immediate, because IP is used as the destination register. For the other
6722 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
6723 // and they can be encoded in the instruction without making use of IP register.
6724 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
6725
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006726 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006727 // Jump to successors[0] if value == lower_bound.
6728 __ b(codegen_->GetLabelOf(successors[0]), EQ);
6729 int32_t last_index = 0;
6730 for (; num_entries - last_index > 2; last_index += 2) {
6731 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
6732 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6733 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
6734 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6735 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
6736 }
6737 if (num_entries - last_index == 2) {
6738 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00006739 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006740 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006741 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04006742
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07006743 // And the default for any other value.
6744 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
6745 __ b(codegen_->GetLabelOf(default_block));
6746 }
6747 } else {
6748 // Create a table lookup.
6749 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
6750
6751 // Materialize a pointer to the switch table
6752 std::vector<Label*> labels(num_entries);
6753 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
6754 for (uint32_t i = 0; i < num_entries; i++) {
6755 labels[i] = codegen_->GetLabelOf(successors[i]);
6756 }
6757 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
6758
6759 // Remove the bias.
6760 Register key_reg;
6761 if (lower_bound != 0) {
6762 key_reg = locations->GetTemp(1).AsRegister<Register>();
6763 __ AddConstant(key_reg, value_reg, -lower_bound);
6764 } else {
6765 key_reg = value_reg;
6766 }
6767
6768 // Check whether the value is in the table, jump to default block if not.
6769 __ CmpConstant(key_reg, num_entries - 1);
6770 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
6771
6772 // Load the displacement from the table.
6773 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
6774
6775 // Dispatch is a direct add to the PC (for Thumb2).
6776 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04006777 }
6778}
6779
Vladimir Markob4536b72015-11-24 13:45:23 +00006780void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6781 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6782 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00006783}
6784
6785void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
6786 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006787 CodeGeneratorARM::PcRelativePatchInfo* labels =
6788 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00006789 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006790 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006791 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006792 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00006793 __ BindTrackedLabel(&labels->add_pc_label);
6794 __ add(base_reg, base_reg, ShifterOperand(PC));
6795}
6796
Andreas Gampe85b62f22015-09-09 13:15:38 -07006797void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
6798 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00006799 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07006800 return;
6801 }
6802
6803 DCHECK_NE(type, Primitive::kPrimVoid);
6804
6805 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
6806 if (return_loc.Equals(trg)) {
6807 return;
6808 }
6809
6810 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6811 // with the last branch.
6812 if (type == Primitive::kPrimLong) {
6813 HParallelMove parallel_move(GetGraph()->GetArena());
6814 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
6815 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
6816 GetMoveResolver()->EmitNativeCode(&parallel_move);
6817 } else if (type == Primitive::kPrimDouble) {
6818 HParallelMove parallel_move(GetGraph()->GetArena());
6819 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
6820 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
6821 GetMoveResolver()->EmitNativeCode(&parallel_move);
6822 } else {
6823 // Let the parallel move resolver take care of all of this.
6824 HParallelMove parallel_move(GetGraph()->GetArena());
6825 parallel_move.AddMove(return_loc, trg, type, nullptr);
6826 GetMoveResolver()->EmitNativeCode(&parallel_move);
6827 }
6828}
6829
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006830void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
6831 LocationSummary* locations =
6832 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6833 locations->SetInAt(0, Location::RequiresRegister());
6834 locations->SetOut(Location::RequiresRegister());
6835}
6836
6837void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
6838 LocationSummary* locations = instruction->GetLocations();
6839 uint32_t method_offset = 0;
Vladimir Markoa1de9182016-02-25 11:37:38 +00006840 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006841 method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6842 instruction->GetIndex(), kArmPointerSize).SizeValue();
6843 } else {
6844 method_offset = mirror::Class::EmbeddedImTableEntryOffset(
6845 instruction->GetIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
6846 }
6847 __ LoadFromOffset(kLoadWord,
6848 locations->Out().AsRegister<Register>(),
6849 locations->InAt(0).AsRegister<Register>(),
6850 method_offset);
6851}
6852
Roland Levillain4d027112015-07-01 15:41:14 +01006853#undef __
6854#undef QUICK_ENTRY_POINT
6855
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006856} // namespace arm
6857} // namespace art