blob: a7dbb5338209697f497727a24a0a256915676815 [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
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000037namespace arm {
38
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000039static bool ExpectedPairLayout(Location location) {
40 // We expected this for both core and fpu register pairs.
41 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
42}
43
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010044static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010045static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010046
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000047// We unconditionally allocate R5 to ensure we can do long operations
48// with baseline.
49static constexpr Register kCoreSavedRegisterForBaseline = R5;
50static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070051 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000052static constexpr SRegister kFpuCalleeSaves[] =
53 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010054
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000055// D31 cannot be split into two S registers, and the register allocator only works on
56// S registers. Therefore there is no need to block it.
57static constexpr DRegister DTMP = D31;
58
Roland Levillain62a46b22015-06-01 18:24:13 +010059#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010060#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061
Andreas Gampe85b62f22015-09-09 13:15:38 -070062class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010064 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065
Alexandre Rames67555f72014-11-18 10:55:16 +000066 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010067 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000069 if (instruction_->CanThrowIntoCatchBlock()) {
70 // Live registers will be restored in the catch block if caught.
71 SaveLiveRegisters(codegen, instruction_->GetLocations());
72 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010073 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000074 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010075 }
76
Alexandre Rames8158f282015-08-07 10:26:17 +010077 bool IsFatal() const OVERRIDE { return true; }
78
Alexandre Rames9931f312015-06-19 14:47:01 +010079 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
80
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010082 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010083 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
84};
85
Andreas Gampe85b62f22015-09-09 13:15:38 -070086class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000087 public:
88 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
89
Alexandre Rames67555f72014-11-18 10:55:16 +000090 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000091 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
92 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000093 if (instruction_->CanThrowIntoCatchBlock()) {
94 // Live registers will be restored in the catch block if caught.
95 SaveLiveRegisters(codegen, instruction_->GetLocations());
96 }
Calin Juravled0d48522014-11-04 16:40:20 +000097 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000098 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +000099 }
100
Alexandre Rames8158f282015-08-07 10:26:17 +0100101 bool IsFatal() const OVERRIDE { return true; }
102
Alexandre Rames9931f312015-06-19 14:47:01 +0100103 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
104
Calin Juravled0d48522014-11-04 16:40:20 +0000105 private:
106 HDivZeroCheck* const instruction_;
107 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
108};
109
Andreas Gampe85b62f22015-09-09 13:15:38 -0700110class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000111 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000112 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100113 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000114
Alexandre Rames67555f72014-11-18 10:55:16 +0000115 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100116 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000117 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000118 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100119 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000120 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000121 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100122 if (successor_ == nullptr) {
123 __ b(GetReturnLabel());
124 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100125 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100126 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000127 }
128
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100129 Label* GetReturnLabel() {
130 DCHECK(successor_ == nullptr);
131 return &return_label_;
132 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000133
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100134 HBasicBlock* GetSuccessor() const {
135 return successor_;
136 }
137
Alexandre Rames9931f312015-06-19 14:47:01 +0100138 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
139
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 private:
141 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100142 // If not null, the block to branch to after the suspend check.
143 HBasicBlock* const successor_;
144
145 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000146 Label return_label_;
147
148 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
149};
150
Andreas Gampe85b62f22015-09-09 13:15:38 -0700151class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100152 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100153 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
154 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100155
Alexandre Rames67555f72014-11-18 10:55:16 +0000156 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100157 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100158 LocationSummary* locations = instruction_->GetLocations();
159
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000161 if (instruction_->CanThrowIntoCatchBlock()) {
162 // Live registers will be restored in the catch block if caught.
163 SaveLiveRegisters(codegen, instruction_->GetLocations());
164 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000165 // We're moving two locations to locations that could overlap, so we need a parallel
166 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100167 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000168 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100169 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000170 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100171 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100172 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100173 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
174 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100175 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000176 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100177 }
178
Alexandre Rames8158f282015-08-07 10:26:17 +0100179 bool IsFatal() const OVERRIDE { return true; }
180
Alexandre Rames9931f312015-06-19 14:47:01 +0100181 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
182
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100183 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100184 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185
186 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
187};
188
Andreas Gampe85b62f22015-09-09 13:15:38 -0700189class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100190 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000191 LoadClassSlowPathARM(HLoadClass* cls,
192 HInstruction* at,
193 uint32_t dex_pc,
194 bool do_clinit)
195 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
196 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
197 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100198
Alexandre Rames67555f72014-11-18 10:55:16 +0000199 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000200 LocationSummary* locations = at_->GetLocations();
201
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100202 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
203 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000204 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100205
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100206 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000207 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 int32_t entry_point_offset = do_clinit_
209 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
210 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000211 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000212
213 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000214 Location out = locations->Out();
215 if (out.IsValid()) {
216 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000217 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
218 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000219 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100220 __ b(GetExitLabel());
221 }
222
Alexandre Rames9931f312015-06-19 14:47:01 +0100223 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
224
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100225 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000226 // The class this slow path will load.
227 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100228
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000229 // The instruction where this slow path is happening.
230 // (Might be the load class or an initialization check).
231 HInstruction* const at_;
232
233 // The dex PC of `at_`.
234 const uint32_t dex_pc_;
235
236 // Whether to initialize the class.
237 const bool do_clinit_;
238
239 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100240};
241
Andreas Gampe85b62f22015-09-09 13:15:38 -0700242class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000243 public:
244 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
245
Alexandre Rames67555f72014-11-18 10:55:16 +0000246 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000247 LocationSummary* locations = instruction_->GetLocations();
248 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
249
250 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
251 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000252 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000253
254 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800255 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000256 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000257 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000258 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
259
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000260 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000261 __ b(GetExitLabel());
262 }
263
Alexandre Rames9931f312015-06-19 14:47:01 +0100264 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
265
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000266 private:
267 HLoadString* const instruction_;
268
269 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
270};
271
Andreas Gampe85b62f22015-09-09 13:15:38 -0700272class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000273 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000274 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
275 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000276
Alexandre Rames67555f72014-11-18 10:55:16 +0000277 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100279 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
280 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000281 DCHECK(instruction_->IsCheckCast()
282 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000283
284 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
285 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000286
287 if (instruction_->IsCheckCast()) {
288 // The codegen for the instruction overwrites `temp`, so put it back in place.
289 Register obj = locations->InAt(0).AsRegister<Register>();
290 Register temp = locations->GetTemp(0).AsRegister<Register>();
291 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
292 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
293 __ MaybeUnpoisonHeapReference(temp);
294 }
295
296 if (!is_fatal_) {
297 SaveLiveRegisters(codegen, locations);
298 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299
300 // We're moving two locations to locations that could overlap, so we need a parallel
301 // move resolver.
302 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000303 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100304 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000305 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100306 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100307 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100308 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
309 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000310
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000311 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100312 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
313 instruction_,
314 instruction_->GetDexPc(),
315 this);
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);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000323 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000324
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000325 if (!is_fatal_) {
326 RestoreLiveRegisters(codegen, locations);
327 __ b(GetExitLabel());
328 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000329 }
330
Alexandre Rames9931f312015-06-19 14:47:01 +0100331 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
332
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000333 bool IsFatal() const OVERRIDE { return is_fatal_; }
334
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000335 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000336 HInstruction* const instruction_;
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:
344 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
345 : instruction_(instruction) {}
346
347 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
348 __ Bind(GetEntryLabel());
349 SaveLiveRegisters(codegen, instruction_->GetLocations());
350 DCHECK(instruction_->IsDeoptimize());
351 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
352 uint32_t dex_pc = deoptimize->GetDexPc();
353 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
354 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
355 }
356
Alexandre Rames9931f312015-06-19 14:47:01 +0100357 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
358
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700359 private:
360 HInstruction* const instruction_;
361 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
362};
363
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100364class ArraySetSlowPathARM : public SlowPathCode {
365 public:
366 explicit ArraySetSlowPathARM(HInstruction* instruction) : instruction_(instruction) {}
367
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);
397 RestoreLiveRegisters(codegen, locations);
398 __ b(GetExitLabel());
399 }
400
401 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
402
403 private:
404 HInstruction* const instruction_;
405
406 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
407};
408
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000409#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100410#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700411
Roland Levillain4fa13f62015-07-06 18:11:54 +0100412inline Condition ARMSignedOrFPCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700413 switch (cond) {
414 case kCondEQ: return EQ;
415 case kCondNE: return NE;
416 case kCondLT: return LT;
417 case kCondLE: return LE;
418 case kCondGT: return GT;
419 case kCondGE: return GE;
Dave Allison20dfc792014-06-16 20:44:29 -0700420 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100421 LOG(FATAL) << "Unreachable";
422 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700423}
424
Roland Levillain4fa13f62015-07-06 18:11:54 +0100425inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700426 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100427 case kCondEQ: return EQ;
428 case kCondNE: return NE;
429 case kCondLT: return LO;
430 case kCondLE: return LS;
431 case kCondGT: return HI;
432 case kCondGE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700433 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100434 LOG(FATAL) << "Unreachable";
435 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700436}
437
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100438void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100439 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100440}
441
442void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100443 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100444}
445
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100446size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
447 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
448 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100449}
450
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100451size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
452 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
453 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100454}
455
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000456size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
457 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
458 return kArmWordSize;
459}
460
461size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
462 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
463 return kArmWordSize;
464}
465
Calin Juravle34166012014-12-19 17:22:29 +0000466CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000467 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100468 const CompilerOptions& compiler_options,
469 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000470 : CodeGenerator(graph,
471 kNumberOfCoreRegisters,
472 kNumberOfSRegisters,
473 kNumberOfRegisterPairs,
474 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
475 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray88a95ba2015-09-30 17:18:14 +0100476 graph->IsDebuggable()
477 // If the graph is debuggable, we need to save the fpu registers ourselves,
478 // as the stubs do not do it.
479 ? 0
480 : ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
481 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100482 compiler_options,
483 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100484 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100485 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100486 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100487 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000488 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000489 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100490 method_patches_(MethodReferenceComparator(),
491 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
492 call_patches_(MethodReferenceComparator(),
493 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
494 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700495 // Always save the LR register to mimic Quick.
496 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100497}
498
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000499void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
500 // Ensure that we fix up branches and literal loads and emit the literal pool.
501 __ FinalizeCode();
502
503 // Adjust native pc offsets in stack maps.
504 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
505 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
506 uint32_t new_position = __ GetAdjustedPosition(old_position);
507 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
508 }
509 // Adjust native pc offsets of block labels.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100510 for (HBasicBlock* block : *block_order_) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000511 // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
512 // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
Vladimir Marko225b6462015-09-28 12:17:40 +0100513 DCHECK_LT(block->GetBlockId(), GetGraph()->GetBlocks().size());
514 Label* block_label = &block_labels_[block->GetBlockId()];
David Brazdilfc6a86a2015-06-26 10:33:45 +0000515 DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000516 if (block_label->IsBound()) {
517 __ AdjustLabelPosition(block_label);
518 }
519 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100520 // Adjust pc offsets for the disassembly information.
521 if (disasm_info_ != nullptr) {
522 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
523 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
524 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
525 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
526 it.second.start = __ GetAdjustedPosition(it.second.start);
527 it.second.end = __ GetAdjustedPosition(it.second.end);
528 }
529 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
530 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
531 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
532 }
533 }
Vladimir Marko58155012015-08-19 12:49:41 +0000534 // Adjust pc offsets for relative call patches.
535 for (MethodPatchInfo<Label>& info : relative_call_patches_) {
536 __ AdjustLabelPosition(&info.label);
537 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000538
539 CodeGenerator::Finalize(allocator);
540}
541
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100542Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100543 switch (type) {
544 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100545 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100546 ArmManagedRegister pair =
547 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100548 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
549 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
550
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100551 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
552 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100553 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100554 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100555 }
556
557 case Primitive::kPrimByte:
558 case Primitive::kPrimBoolean:
559 case Primitive::kPrimChar:
560 case Primitive::kPrimShort:
561 case Primitive::kPrimInt:
562 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100563 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100564 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100565 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
566 ArmManagedRegister current =
567 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
568 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100569 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100570 }
571 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100572 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100573 }
574
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000575 case Primitive::kPrimFloat: {
576 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100577 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100579
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000580 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000581 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
582 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000583 return Location::FpuRegisterPairLocation(reg, reg + 1);
584 }
585
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100586 case Primitive::kPrimVoid:
587 LOG(FATAL) << "Unreachable type " << type;
588 }
589
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100590 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100591}
592
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000593void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100594 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100595 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100596
597 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100598 blocked_core_registers_[SP] = true;
599 blocked_core_registers_[LR] = true;
600 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100601
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100602 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100603 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100604
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100605 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100606 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100607
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000608 if (is_baseline) {
609 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
610 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
611 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000612
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000613 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
614
615 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
616 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
617 }
618 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100619
620 UpdateBlockedPairRegisters();
621}
622
623void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
624 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
625 ArmManagedRegister current =
626 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
627 if (blocked_core_registers_[current.AsRegisterPairLow()]
628 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
629 blocked_register_pairs_[i] = true;
630 }
631 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100632}
633
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100634InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
635 : HGraphVisitor(graph),
636 assembler_(codegen->GetAssembler()),
637 codegen_(codegen) {}
638
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000639void CodeGeneratorARM::ComputeSpillMask() {
640 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000641 // Save one extra register for baseline. Note that on thumb2, there is no easy
642 // instruction to restore just the PC, so this actually helps both baseline
643 // and non-baseline to save and restore at least two registers at entry and exit.
644 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000645 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
646 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
647 // We use vpush and vpop for saving and restoring floating point registers, which take
648 // a SRegister and the number of registers to save/restore after that SRegister. We
649 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
650 // but in the range.
651 if (fpu_spill_mask_ != 0) {
652 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
653 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
654 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
655 fpu_spill_mask_ |= (1 << i);
656 }
657 }
658}
659
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100660static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100661 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100662}
663
664static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100665 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100666}
667
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000668void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000669 bool skip_overflow_check =
670 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000671 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000672 __ Bind(&frame_entry_label_);
673
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000674 if (HasEmptyFrame()) {
675 return;
676 }
677
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100678 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000679 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
680 __ LoadFromOffset(kLoadWord, IP, IP, 0);
681 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100682 }
683
Andreas Gampe501fd632015-09-10 16:11:06 -0700684 __ PushList(core_spill_mask_);
685 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
686 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000687 if (fpu_spill_mask_ != 0) {
688 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
689 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100690 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100691 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000692 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100693 int adjust = GetFrameSize() - FrameEntrySpillSize();
694 __ AddConstant(SP, -adjust);
695 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100696 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000697}
698
699void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000700 if (HasEmptyFrame()) {
701 __ bx(LR);
702 return;
703 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100704 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100705 int adjust = GetFrameSize() - FrameEntrySpillSize();
706 __ AddConstant(SP, adjust);
707 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000708 if (fpu_spill_mask_ != 0) {
709 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
710 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100711 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
712 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000713 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700714 // Pop LR into PC to return.
715 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
716 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
717 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100718 __ cfi().RestoreState();
719 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000720}
721
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100722void CodeGeneratorARM::Bind(HBasicBlock* block) {
723 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000724}
725
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100726Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
727 switch (load->GetType()) {
728 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100729 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100730 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100731
732 case Primitive::kPrimInt:
733 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100734 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100735 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100736
737 case Primitive::kPrimBoolean:
738 case Primitive::kPrimByte:
739 case Primitive::kPrimChar:
740 case Primitive::kPrimShort:
741 case Primitive::kPrimVoid:
742 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700743 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100744 }
745
746 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700747 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100748}
749
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100750Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100751 switch (type) {
752 case Primitive::kPrimBoolean:
753 case Primitive::kPrimByte:
754 case Primitive::kPrimChar:
755 case Primitive::kPrimShort:
756 case Primitive::kPrimInt:
757 case Primitive::kPrimNot: {
758 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000759 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100760 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100761 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100762 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000763 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100764 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100765 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100766
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000767 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100768 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000769 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100770 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000771 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100772 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000773 if (calling_convention.GetRegisterAt(index) == R1) {
774 // Skip R1, and use R2_R3 instead.
775 gp_index_++;
776 index++;
777 }
778 }
779 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
780 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000781 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100782
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000783 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000784 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100785 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000786 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
787 }
788 }
789
790 case Primitive::kPrimFloat: {
791 uint32_t stack_index = stack_index_++;
792 if (float_index_ % 2 == 0) {
793 float_index_ = std::max(double_index_, float_index_);
794 }
795 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
796 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
797 } else {
798 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
799 }
800 }
801
802 case Primitive::kPrimDouble: {
803 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
804 uint32_t stack_index = stack_index_;
805 stack_index_ += 2;
806 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
807 uint32_t index = double_index_;
808 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000809 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000810 calling_convention.GetFpuRegisterAt(index),
811 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000812 DCHECK(ExpectedPairLayout(result));
813 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000814 } else {
815 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100816 }
817 }
818
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100819 case Primitive::kPrimVoid:
820 LOG(FATAL) << "Unexpected parameter type " << type;
821 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100822 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100823 return Location();
824}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100825
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100826Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000827 switch (type) {
828 case Primitive::kPrimBoolean:
829 case Primitive::kPrimByte:
830 case Primitive::kPrimChar:
831 case Primitive::kPrimShort:
832 case Primitive::kPrimInt:
833 case Primitive::kPrimNot: {
834 return Location::RegisterLocation(R0);
835 }
836
837 case Primitive::kPrimFloat: {
838 return Location::FpuRegisterLocation(S0);
839 }
840
841 case Primitive::kPrimLong: {
842 return Location::RegisterPairLocation(R0, R1);
843 }
844
845 case Primitive::kPrimDouble: {
846 return Location::FpuRegisterPairLocation(S0, S1);
847 }
848
849 case Primitive::kPrimVoid:
850 return Location();
851 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100852
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000853 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000854}
855
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100856Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
857 return Location::RegisterLocation(kMethodRegisterArgument);
858}
859
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100860void CodeGeneratorARM::Move32(Location destination, Location source) {
861 if (source.Equals(destination)) {
862 return;
863 }
864 if (destination.IsRegister()) {
865 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000866 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100867 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000868 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100869 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000870 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100871 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100872 } else if (destination.IsFpuRegister()) {
873 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000874 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000876 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100877 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000878 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100879 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100880 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000881 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000883 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100884 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000885 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000887 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100888 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
889 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 }
891 }
892}
893
894void CodeGeneratorARM::Move64(Location destination, Location source) {
895 if (source.Equals(destination)) {
896 return;
897 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100898 if (destination.IsRegisterPair()) {
899 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000900 EmitParallelMoves(
901 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
902 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100903 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000904 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100905 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
906 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100907 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000908 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100909 } else {
910 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000911 DCHECK(ExpectedPairLayout(destination));
912 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
913 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100914 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000915 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100916 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000917 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
918 SP,
919 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100920 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000921 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100922 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100923 } else {
924 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100925 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000926 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100927 if (source.AsRegisterPairLow<Register>() == R1) {
928 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100929 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
930 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100931 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100932 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100933 SP, destination.GetStackIndex());
934 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000935 } else if (source.IsFpuRegisterPair()) {
936 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
937 SP,
938 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100939 } else {
940 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000941 EmitParallelMoves(
942 Location::StackSlot(source.GetStackIndex()),
943 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100944 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000945 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100946 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
947 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100948 }
949 }
950}
951
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100952void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100953 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100954 if (instruction->IsCurrentMethod()) {
955 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
956 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100957 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100958 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000959 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000960 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
961 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000962 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000963 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000964 } else {
965 DCHECK(location.IsStackSlot());
966 __ LoadImmediate(IP, value);
967 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
968 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000969 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000970 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000971 int64_t value = const_to_move->AsLongConstant()->GetValue();
972 if (location.IsRegisterPair()) {
973 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
974 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
975 } else {
976 DCHECK(location.IsDoubleStackSlot());
977 __ LoadImmediate(IP, Low32Bits(value));
978 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
979 __ LoadImmediate(IP, High32Bits(value));
980 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
981 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100982 }
Roland Levillain476df552014-10-09 17:51:36 +0100983 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100984 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
985 switch (instruction->GetType()) {
986 case Primitive::kPrimBoolean:
987 case Primitive::kPrimByte:
988 case Primitive::kPrimChar:
989 case Primitive::kPrimShort:
990 case Primitive::kPrimInt:
991 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100992 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100993 Move32(location, Location::StackSlot(stack_slot));
994 break;
995
996 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100997 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100998 Move64(location, Location::DoubleStackSlot(stack_slot));
999 break;
1000
1001 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001002 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001003 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001004 } else if (instruction->IsTemporary()) {
1005 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +00001006 if (temp_location.IsStackSlot()) {
1007 Move32(location, temp_location);
1008 } else {
1009 DCHECK(temp_location.IsDoubleStackSlot());
1010 Move64(location, temp_location);
1011 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001012 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001013 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001014 switch (instruction->GetType()) {
1015 case Primitive::kPrimBoolean:
1016 case Primitive::kPrimByte:
1017 case Primitive::kPrimChar:
1018 case Primitive::kPrimShort:
1019 case Primitive::kPrimNot:
1020 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001021 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001022 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001023 break;
1024
1025 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001026 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001027 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001028 break;
1029
1030 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001031 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001032 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001033 }
1034}
1035
Calin Juravle175dc732015-08-25 15:42:32 +01001036void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1037 DCHECK(location.IsRegister());
1038 __ LoadImmediate(location.AsRegister<Register>(), value);
1039}
1040
1041void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1042 HInstruction* instruction,
1043 uint32_t dex_pc,
1044 SlowPathCode* slow_path) {
1045 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1046 instruction,
1047 dex_pc,
1048 slow_path);
1049}
1050
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001051void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1052 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001053 uint32_t dex_pc,
1054 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001055 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001056 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1057 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001058 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001059}
1060
David Brazdilfc6a86a2015-06-26 10:33:45 +00001061void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001062 DCHECK(!successor->IsExitBlock());
1063
1064 HBasicBlock* block = got->GetBlock();
1065 HInstruction* previous = got->GetPrevious();
1066
1067 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001068 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001069 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1070 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1071 return;
1072 }
1073
1074 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1075 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1076 }
1077 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001078 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001079 }
1080}
1081
David Brazdilfc6a86a2015-06-26 10:33:45 +00001082void LocationsBuilderARM::VisitGoto(HGoto* got) {
1083 got->SetLocations(nullptr);
1084}
1085
1086void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1087 HandleGoto(got, got->GetSuccessor());
1088}
1089
1090void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1091 try_boundary->SetLocations(nullptr);
1092}
1093
1094void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1095 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1096 if (!successor->IsExitBlock()) {
1097 HandleGoto(try_boundary, successor);
1098 }
1099}
1100
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001101void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001102 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001103}
1104
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001105void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001106 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001107}
1108
Roland Levillain4fa13f62015-07-06 18:11:54 +01001109void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1110 ShifterOperand operand;
1111 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1112 __ cmp(left, operand);
1113 } else {
1114 Register temp = IP;
1115 __ LoadImmediate(temp, right);
1116 __ cmp(left, ShifterOperand(temp));
1117 }
1118}
1119
1120void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1121 Label* true_label,
1122 Label* false_label) {
1123 __ vmstat(); // transfer FP status register to ARM APSR.
1124 if (cond->IsFPConditionTrueIfNaN()) {
1125 __ b(true_label, VS); // VS for unordered.
1126 } else if (cond->IsFPConditionFalseIfNaN()) {
1127 __ b(false_label, VS); // VS for unordered.
1128 }
1129 __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
1130}
1131
1132void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1133 Label* true_label,
1134 Label* false_label) {
1135 LocationSummary* locations = cond->GetLocations();
1136 Location left = locations->InAt(0);
1137 Location right = locations->InAt(1);
1138 IfCondition if_cond = cond->GetCondition();
1139
1140 Register left_high = left.AsRegisterPairHigh<Register>();
1141 Register left_low = left.AsRegisterPairLow<Register>();
1142 IfCondition true_high_cond = if_cond;
1143 IfCondition false_high_cond = cond->GetOppositeCondition();
1144 Condition final_condition = ARMUnsignedCondition(if_cond);
1145
1146 // Set the conditions for the test, remembering that == needs to be
1147 // decided using the low words.
1148 switch (if_cond) {
1149 case kCondEQ:
1150 case kCondNE:
1151 // Nothing to do.
1152 break;
1153 case kCondLT:
1154 false_high_cond = kCondGT;
1155 break;
1156 case kCondLE:
1157 true_high_cond = kCondLT;
1158 break;
1159 case kCondGT:
1160 false_high_cond = kCondLT;
1161 break;
1162 case kCondGE:
1163 true_high_cond = kCondGT;
1164 break;
1165 }
1166 if (right.IsConstant()) {
1167 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1168 int32_t val_low = Low32Bits(value);
1169 int32_t val_high = High32Bits(value);
1170
1171 GenerateCompareWithImmediate(left_high, val_high);
1172 if (if_cond == kCondNE) {
1173 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1174 } else if (if_cond == kCondEQ) {
1175 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1176 } else {
1177 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1178 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1179 }
1180 // Must be equal high, so compare the lows.
1181 GenerateCompareWithImmediate(left_low, val_low);
1182 } else {
1183 Register right_high = right.AsRegisterPairHigh<Register>();
1184 Register right_low = right.AsRegisterPairLow<Register>();
1185
1186 __ cmp(left_high, ShifterOperand(right_high));
1187 if (if_cond == kCondNE) {
1188 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1189 } else if (if_cond == kCondEQ) {
1190 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1191 } else {
1192 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1193 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1194 }
1195 // Must be equal high, so compare the lows.
1196 __ cmp(left_low, ShifterOperand(right_low));
1197 }
1198 // The last comparison might be unsigned.
1199 __ b(true_label, final_condition);
1200}
1201
1202void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
1203 HCondition* condition,
1204 Label* true_target,
1205 Label* false_target,
1206 Label* always_true_target) {
1207 LocationSummary* locations = condition->GetLocations();
1208 Location left = locations->InAt(0);
1209 Location right = locations->InAt(1);
1210
1211 // We don't want true_target as a nullptr.
1212 if (true_target == nullptr) {
1213 true_target = always_true_target;
1214 }
1215 bool falls_through = (false_target == nullptr);
1216
1217 // FP compares don't like null false_targets.
1218 if (false_target == nullptr) {
1219 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1220 }
1221
1222 Primitive::Type type = condition->InputAt(0)->GetType();
1223 switch (type) {
1224 case Primitive::kPrimLong:
1225 GenerateLongComparesAndJumps(condition, true_target, false_target);
1226 break;
1227 case Primitive::kPrimFloat:
1228 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1229 GenerateFPJumps(condition, true_target, false_target);
1230 break;
1231 case Primitive::kPrimDouble:
1232 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1233 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1234 GenerateFPJumps(condition, true_target, false_target);
1235 break;
1236 default:
1237 LOG(FATAL) << "Unexpected compare type " << type;
1238 }
1239
1240 if (!falls_through) {
1241 __ b(false_target);
1242 }
1243}
1244
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001245void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1246 Label* true_target,
1247 Label* false_target,
1248 Label* always_true_target) {
1249 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001250 if (cond->IsIntConstant()) {
1251 // Constant condition, statically compared against 1.
1252 int32_t cond_value = cond->AsIntConstant()->GetValue();
1253 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001254 if (always_true_target != nullptr) {
1255 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001256 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001257 return;
1258 } else {
1259 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001260 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001261 } else {
1262 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1263 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001264 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01001265 __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
1266 true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001267 } else {
1268 // Condition has not been materialized, use its inputs as the
1269 // comparison and its condition as the branch condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001270 Primitive::Type type =
1271 cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
1272 // Is this a long or FP comparison that has been folded into the HCondition?
1273 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1274 // Generate the comparison directly.
1275 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1276 true_target, false_target, always_true_target);
1277 return;
1278 }
1279
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001280 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001281 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001282 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001283 Location right = locations->InAt(1);
1284 if (right.IsRegister()) {
1285 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001286 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001287 DCHECK(right.IsConstant());
1288 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001289 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001290 __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001291 }
Dave Allison20dfc792014-06-16 20:44:29 -07001292 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001293 if (false_target != nullptr) {
1294 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001295 }
1296}
1297
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001298void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1299 LocationSummary* locations =
1300 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1301 HInstruction* cond = if_instr->InputAt(0);
1302 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1303 locations->SetInAt(0, Location::RequiresRegister());
1304 }
1305}
1306
1307void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1308 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1309 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1310 Label* always_true_target = true_target;
1311 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1312 if_instr->IfTrueSuccessor())) {
1313 always_true_target = nullptr;
1314 }
1315 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1316 if_instr->IfFalseSuccessor())) {
1317 false_target = nullptr;
1318 }
1319 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1320}
1321
1322void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1323 LocationSummary* locations = new (GetGraph()->GetArena())
1324 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1325 HInstruction* cond = deoptimize->InputAt(0);
1326 DCHECK(cond->IsCondition());
1327 if (cond->AsCondition()->NeedsMaterialization()) {
1328 locations->SetInAt(0, Location::RequiresRegister());
1329 }
1330}
1331
1332void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001333 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001334 DeoptimizationSlowPathARM(deoptimize);
1335 codegen_->AddSlowPath(slow_path);
1336 Label* slow_path_entry = slow_path->GetEntryLabel();
1337 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1338}
Dave Allison20dfc792014-06-16 20:44:29 -07001339
Roland Levillain0d37cd02015-05-27 16:39:19 +01001340void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001341 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001342 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001343 // Handle the long/FP comparisons made in instruction simplification.
1344 switch (cond->InputAt(0)->GetType()) {
1345 case Primitive::kPrimLong:
1346 locations->SetInAt(0, Location::RequiresRegister());
1347 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1348 if (cond->NeedsMaterialization()) {
1349 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1350 }
1351 break;
1352
1353 case Primitive::kPrimFloat:
1354 case Primitive::kPrimDouble:
1355 locations->SetInAt(0, Location::RequiresFpuRegister());
1356 locations->SetInAt(1, Location::RequiresFpuRegister());
1357 if (cond->NeedsMaterialization()) {
1358 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1359 }
1360 break;
1361
1362 default:
1363 locations->SetInAt(0, Location::RequiresRegister());
1364 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1365 if (cond->NeedsMaterialization()) {
1366 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1367 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001368 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001369}
1370
Roland Levillain0d37cd02015-05-27 16:39:19 +01001371void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001372 if (!cond->NeedsMaterialization()) {
1373 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001374 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001375
1376 LocationSummary* locations = cond->GetLocations();
1377 Location left = locations->InAt(0);
1378 Location right = locations->InAt(1);
1379 Register out = locations->Out().AsRegister<Register>();
1380 Label true_label, false_label;
1381
1382 switch (cond->InputAt(0)->GetType()) {
1383 default: {
1384 // Integer case.
1385 if (right.IsRegister()) {
1386 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1387 } else {
1388 DCHECK(right.IsConstant());
1389 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1390 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1391 }
1392 __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
1393 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1394 ARMSignedOrFPCondition(cond->GetCondition()));
1395 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1396 ARMSignedOrFPCondition(cond->GetOppositeCondition()));
1397 return;
1398 }
1399 case Primitive::kPrimLong:
1400 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1401 break;
1402 case Primitive::kPrimFloat:
1403 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1404 GenerateFPJumps(cond, &true_label, &false_label);
1405 break;
1406 case Primitive::kPrimDouble:
1407 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1408 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1409 GenerateFPJumps(cond, &true_label, &false_label);
1410 break;
1411 }
1412
1413 // Convert the jumps into the result.
1414 Label done_label;
1415
1416 // False case: result = 0.
1417 __ Bind(&false_label);
1418 __ LoadImmediate(out, 0);
1419 __ b(&done_label);
1420
1421 // True case: result = 1.
1422 __ Bind(&true_label);
1423 __ LoadImmediate(out, 1);
1424 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001425}
1426
1427void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1428 VisitCondition(comp);
1429}
1430
1431void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1432 VisitCondition(comp);
1433}
1434
1435void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1436 VisitCondition(comp);
1437}
1438
1439void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1440 VisitCondition(comp);
1441}
1442
1443void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1444 VisitCondition(comp);
1445}
1446
1447void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1448 VisitCondition(comp);
1449}
1450
1451void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1452 VisitCondition(comp);
1453}
1454
1455void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1456 VisitCondition(comp);
1457}
1458
1459void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1460 VisitCondition(comp);
1461}
1462
1463void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1464 VisitCondition(comp);
1465}
1466
1467void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1468 VisitCondition(comp);
1469}
1470
1471void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1472 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001473}
1474
1475void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001476 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001477}
1478
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001479void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1480 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001481}
1482
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001483void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001484 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001485}
1486
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001487void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001488 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001489 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001490}
1491
1492void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001493 LocationSummary* locations =
1494 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001495 switch (store->InputAt(1)->GetType()) {
1496 case Primitive::kPrimBoolean:
1497 case Primitive::kPrimByte:
1498 case Primitive::kPrimChar:
1499 case Primitive::kPrimShort:
1500 case Primitive::kPrimInt:
1501 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001502 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001503 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1504 break;
1505
1506 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001507 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001508 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1509 break;
1510
1511 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001512 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001513 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001514}
1515
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001516void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001517 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001518}
1519
1520void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001521 LocationSummary* locations =
1522 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001523 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001524}
1525
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001526void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001527 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001528 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001529}
1530
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001531void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1532 LocationSummary* locations =
1533 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1534 locations->SetOut(Location::ConstantLocation(constant));
1535}
1536
1537void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1538 // Will be generated at use site.
1539 UNUSED(constant);
1540}
1541
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001542void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001543 LocationSummary* locations =
1544 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001545 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001546}
1547
1548void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1549 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001550 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001551}
1552
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001553void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1554 LocationSummary* locations =
1555 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1556 locations->SetOut(Location::ConstantLocation(constant));
1557}
1558
1559void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1560 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001561 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001562}
1563
1564void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1565 LocationSummary* locations =
1566 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1567 locations->SetOut(Location::ConstantLocation(constant));
1568}
1569
1570void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1571 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001572 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001573}
1574
Calin Juravle27df7582015-04-17 19:12:31 +01001575void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1576 memory_barrier->SetLocations(nullptr);
1577}
1578
1579void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1580 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1581}
1582
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001583void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001584 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001585}
1586
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001587void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001588 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001589 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001590}
1591
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001592void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001593 LocationSummary* locations =
1594 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001595 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001596}
1597
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001598void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001599 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001600 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001601}
1602
Calin Juravle175dc732015-08-25 15:42:32 +01001603void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1604 // The trampoline uses the same calling convention as dex calling conventions,
1605 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1606 // the method_idx.
1607 HandleInvoke(invoke);
1608}
1609
1610void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1611 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1612}
1613
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001614void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001615 // When we do not run baseline, explicit clinit checks triggered by static
1616 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1617 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001618
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001619 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1620 codegen_->GetInstructionSetFeatures());
1621 if (intrinsic.TryDispatch(invoke)) {
1622 return;
1623 }
1624
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001625 HandleInvoke(invoke);
1626}
1627
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001628static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1629 if (invoke->GetLocations()->Intrinsified()) {
1630 IntrinsicCodeGeneratorARM intrinsic(codegen);
1631 intrinsic.Dispatch(invoke);
1632 return true;
1633 }
1634 return false;
1635}
1636
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001637void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001638 // When we do not run baseline, explicit clinit checks triggered by static
1639 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1640 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001641
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001642 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1643 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001644 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001645
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001646 LocationSummary* locations = invoke->GetLocations();
1647 codegen_->GenerateStaticOrDirectCall(
1648 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001649 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001650}
1651
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001652void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001653 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001654 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001655}
1656
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001657void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001658 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1659 codegen_->GetInstructionSetFeatures());
1660 if (intrinsic.TryDispatch(invoke)) {
1661 return;
1662 }
1663
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001664 HandleInvoke(invoke);
1665}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001666
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001667void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001668 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1669 return;
1670 }
1671
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001672 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001673 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001674 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001675}
1676
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001677void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1678 HandleInvoke(invoke);
1679 // Add the hidden argument.
1680 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1681}
1682
1683void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1684 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001685 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001686 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1687 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001688 LocationSummary* locations = invoke->GetLocations();
1689 Location receiver = locations->InAt(0);
1690 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1691
1692 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001693 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1694 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001695
1696 // temp = object->GetClass();
1697 if (receiver.IsStackSlot()) {
1698 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1699 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1700 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001701 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001702 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001703 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001704 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001705 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001706 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001707 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001708 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1709 // LR = temp->GetEntryPoint();
1710 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1711 // LR();
1712 __ blx(LR);
1713 DCHECK(!codegen_->IsLeafMethod());
1714 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1715}
1716
Roland Levillain88cb1752014-10-20 16:36:47 +01001717void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1718 LocationSummary* locations =
1719 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1720 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001721 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001722 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001723 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1724 break;
1725 }
1726 case Primitive::kPrimLong: {
1727 locations->SetInAt(0, Location::RequiresRegister());
1728 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001729 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001730 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001731
Roland Levillain88cb1752014-10-20 16:36:47 +01001732 case Primitive::kPrimFloat:
1733 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001734 locations->SetInAt(0, Location::RequiresFpuRegister());
1735 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001736 break;
1737
1738 default:
1739 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1740 }
1741}
1742
1743void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1744 LocationSummary* locations = neg->GetLocations();
1745 Location out = locations->Out();
1746 Location in = locations->InAt(0);
1747 switch (neg->GetResultType()) {
1748 case Primitive::kPrimInt:
1749 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001750 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001751 break;
1752
1753 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001754 DCHECK(in.IsRegisterPair());
1755 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1756 __ rsbs(out.AsRegisterPairLow<Register>(),
1757 in.AsRegisterPairLow<Register>(),
1758 ShifterOperand(0));
1759 // We cannot emit an RSC (Reverse Subtract with Carry)
1760 // instruction here, as it does not exist in the Thumb-2
1761 // instruction set. We use the following approach
1762 // using SBC and SUB instead.
1763 //
1764 // out.hi = -C
1765 __ sbc(out.AsRegisterPairHigh<Register>(),
1766 out.AsRegisterPairHigh<Register>(),
1767 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1768 // out.hi = out.hi - in.hi
1769 __ sub(out.AsRegisterPairHigh<Register>(),
1770 out.AsRegisterPairHigh<Register>(),
1771 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1772 break;
1773
Roland Levillain88cb1752014-10-20 16:36:47 +01001774 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001775 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001776 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001777 break;
1778
Roland Levillain88cb1752014-10-20 16:36:47 +01001779 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001780 DCHECK(in.IsFpuRegisterPair());
1781 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1782 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001783 break;
1784
1785 default:
1786 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1787 }
1788}
1789
Roland Levillaindff1f282014-11-05 14:15:05 +00001790void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001791 Primitive::Type result_type = conversion->GetResultType();
1792 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001793 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001794
Roland Levillain5b3ee562015-04-14 16:02:41 +01001795 // The float-to-long, double-to-long and long-to-float type conversions
1796 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001797 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001798 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1799 && result_type == Primitive::kPrimLong)
1800 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001801 ? LocationSummary::kCall
1802 : LocationSummary::kNoCall;
1803 LocationSummary* locations =
1804 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1805
David Brazdilb2bd1c52015-03-25 11:17:37 +00001806 // The Java language does not allow treating boolean as an integral type but
1807 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001808
Roland Levillaindff1f282014-11-05 14:15:05 +00001809 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001810 case Primitive::kPrimByte:
1811 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001812 case Primitive::kPrimBoolean:
1813 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001814 case Primitive::kPrimShort:
1815 case Primitive::kPrimInt:
1816 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001817 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001818 locations->SetInAt(0, Location::RequiresRegister());
1819 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1820 break;
1821
1822 default:
1823 LOG(FATAL) << "Unexpected type conversion from " << input_type
1824 << " to " << result_type;
1825 }
1826 break;
1827
Roland Levillain01a8d712014-11-14 16:27:39 +00001828 case Primitive::kPrimShort:
1829 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001830 case Primitive::kPrimBoolean:
1831 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001832 case Primitive::kPrimByte:
1833 case Primitive::kPrimInt:
1834 case Primitive::kPrimChar:
1835 // Processing a Dex `int-to-short' instruction.
1836 locations->SetInAt(0, Location::RequiresRegister());
1837 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1838 break;
1839
1840 default:
1841 LOG(FATAL) << "Unexpected type conversion from " << input_type
1842 << " to " << result_type;
1843 }
1844 break;
1845
Roland Levillain946e1432014-11-11 17:35:19 +00001846 case Primitive::kPrimInt:
1847 switch (input_type) {
1848 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001849 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001850 locations->SetInAt(0, Location::Any());
1851 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1852 break;
1853
1854 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001855 // Processing a Dex `float-to-int' instruction.
1856 locations->SetInAt(0, Location::RequiresFpuRegister());
1857 locations->SetOut(Location::RequiresRegister());
1858 locations->AddTemp(Location::RequiresFpuRegister());
1859 break;
1860
Roland Levillain946e1432014-11-11 17:35:19 +00001861 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001862 // Processing a Dex `double-to-int' instruction.
1863 locations->SetInAt(0, Location::RequiresFpuRegister());
1864 locations->SetOut(Location::RequiresRegister());
1865 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001866 break;
1867
1868 default:
1869 LOG(FATAL) << "Unexpected type conversion from " << input_type
1870 << " to " << result_type;
1871 }
1872 break;
1873
Roland Levillaindff1f282014-11-05 14:15:05 +00001874 case Primitive::kPrimLong:
1875 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001876 case Primitive::kPrimBoolean:
1877 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001878 case Primitive::kPrimByte:
1879 case Primitive::kPrimShort:
1880 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001881 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001882 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001883 locations->SetInAt(0, Location::RequiresRegister());
1884 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1885 break;
1886
Roland Levillain624279f2014-12-04 11:54:28 +00001887 case Primitive::kPrimFloat: {
1888 // Processing a Dex `float-to-long' instruction.
1889 InvokeRuntimeCallingConvention calling_convention;
1890 locations->SetInAt(0, Location::FpuRegisterLocation(
1891 calling_convention.GetFpuRegisterAt(0)));
1892 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1893 break;
1894 }
1895
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001896 case Primitive::kPrimDouble: {
1897 // Processing a Dex `double-to-long' instruction.
1898 InvokeRuntimeCallingConvention calling_convention;
1899 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1900 calling_convention.GetFpuRegisterAt(0),
1901 calling_convention.GetFpuRegisterAt(1)));
1902 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001903 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001904 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001905
1906 default:
1907 LOG(FATAL) << "Unexpected type conversion from " << input_type
1908 << " to " << result_type;
1909 }
1910 break;
1911
Roland Levillain981e4542014-11-14 11:47:14 +00001912 case Primitive::kPrimChar:
1913 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001914 case Primitive::kPrimBoolean:
1915 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001916 case Primitive::kPrimByte:
1917 case Primitive::kPrimShort:
1918 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001919 // Processing a Dex `int-to-char' instruction.
1920 locations->SetInAt(0, Location::RequiresRegister());
1921 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1922 break;
1923
1924 default:
1925 LOG(FATAL) << "Unexpected type conversion from " << input_type
1926 << " to " << result_type;
1927 }
1928 break;
1929
Roland Levillaindff1f282014-11-05 14:15:05 +00001930 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001931 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001932 case Primitive::kPrimBoolean:
1933 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001934 case Primitive::kPrimByte:
1935 case Primitive::kPrimShort:
1936 case Primitive::kPrimInt:
1937 case Primitive::kPrimChar:
1938 // Processing a Dex `int-to-float' instruction.
1939 locations->SetInAt(0, Location::RequiresRegister());
1940 locations->SetOut(Location::RequiresFpuRegister());
1941 break;
1942
Roland Levillain5b3ee562015-04-14 16:02:41 +01001943 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001944 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001945 InvokeRuntimeCallingConvention calling_convention;
1946 locations->SetInAt(0, Location::RegisterPairLocation(
1947 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1948 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001949 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001950 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001951
Roland Levillaincff13742014-11-17 14:32:17 +00001952 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001953 // Processing a Dex `double-to-float' instruction.
1954 locations->SetInAt(0, Location::RequiresFpuRegister());
1955 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001956 break;
1957
1958 default:
1959 LOG(FATAL) << "Unexpected type conversion from " << input_type
1960 << " to " << result_type;
1961 };
1962 break;
1963
Roland Levillaindff1f282014-11-05 14:15:05 +00001964 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001965 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001966 case Primitive::kPrimBoolean:
1967 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001968 case Primitive::kPrimByte:
1969 case Primitive::kPrimShort:
1970 case Primitive::kPrimInt:
1971 case Primitive::kPrimChar:
1972 // Processing a Dex `int-to-double' instruction.
1973 locations->SetInAt(0, Location::RequiresRegister());
1974 locations->SetOut(Location::RequiresFpuRegister());
1975 break;
1976
1977 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001978 // Processing a Dex `long-to-double' instruction.
1979 locations->SetInAt(0, Location::RequiresRegister());
1980 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01001981 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001982 locations->AddTemp(Location::RequiresFpuRegister());
1983 break;
1984
Roland Levillaincff13742014-11-17 14:32:17 +00001985 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001986 // Processing a Dex `float-to-double' instruction.
1987 locations->SetInAt(0, Location::RequiresFpuRegister());
1988 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001989 break;
1990
1991 default:
1992 LOG(FATAL) << "Unexpected type conversion from " << input_type
1993 << " to " << result_type;
1994 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001995 break;
1996
1997 default:
1998 LOG(FATAL) << "Unexpected type conversion from " << input_type
1999 << " to " << result_type;
2000 }
2001}
2002
2003void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2004 LocationSummary* locations = conversion->GetLocations();
2005 Location out = locations->Out();
2006 Location in = locations->InAt(0);
2007 Primitive::Type result_type = conversion->GetResultType();
2008 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002009 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002010 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002011 case Primitive::kPrimByte:
2012 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002013 case Primitive::kPrimBoolean:
2014 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002015 case Primitive::kPrimShort:
2016 case Primitive::kPrimInt:
2017 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002018 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002019 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002020 break;
2021
2022 default:
2023 LOG(FATAL) << "Unexpected type conversion from " << input_type
2024 << " to " << result_type;
2025 }
2026 break;
2027
Roland Levillain01a8d712014-11-14 16:27:39 +00002028 case Primitive::kPrimShort:
2029 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002030 case Primitive::kPrimBoolean:
2031 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002032 case Primitive::kPrimByte:
2033 case Primitive::kPrimInt:
2034 case Primitive::kPrimChar:
2035 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002036 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002037 break;
2038
2039 default:
2040 LOG(FATAL) << "Unexpected type conversion from " << input_type
2041 << " to " << result_type;
2042 }
2043 break;
2044
Roland Levillain946e1432014-11-11 17:35:19 +00002045 case Primitive::kPrimInt:
2046 switch (input_type) {
2047 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002048 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002049 DCHECK(out.IsRegister());
2050 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002051 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002052 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002053 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002054 } else {
2055 DCHECK(in.IsConstant());
2056 DCHECK(in.GetConstant()->IsLongConstant());
2057 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002058 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002059 }
2060 break;
2061
Roland Levillain3f8f9362014-12-02 17:45:01 +00002062 case Primitive::kPrimFloat: {
2063 // Processing a Dex `float-to-int' instruction.
2064 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2065 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2066 __ vcvtis(temp, temp);
2067 __ vmovrs(out.AsRegister<Register>(), temp);
2068 break;
2069 }
2070
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002071 case Primitive::kPrimDouble: {
2072 // Processing a Dex `double-to-int' instruction.
2073 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2074 DRegister temp_d = FromLowSToD(temp_s);
2075 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2076 __ vcvtid(temp_s, temp_d);
2077 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002078 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002079 }
Roland Levillain946e1432014-11-11 17:35:19 +00002080
2081 default:
2082 LOG(FATAL) << "Unexpected type conversion from " << input_type
2083 << " to " << result_type;
2084 }
2085 break;
2086
Roland Levillaindff1f282014-11-05 14:15:05 +00002087 case Primitive::kPrimLong:
2088 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002089 case Primitive::kPrimBoolean:
2090 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002091 case Primitive::kPrimByte:
2092 case Primitive::kPrimShort:
2093 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002094 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002095 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002096 DCHECK(out.IsRegisterPair());
2097 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002098 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002099 // Sign extension.
2100 __ Asr(out.AsRegisterPairHigh<Register>(),
2101 out.AsRegisterPairLow<Register>(),
2102 31);
2103 break;
2104
2105 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002106 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002107 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2108 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002109 conversion->GetDexPc(),
2110 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002111 break;
2112
Roland Levillaindff1f282014-11-05 14:15:05 +00002113 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002114 // Processing a Dex `double-to-long' instruction.
2115 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2116 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002117 conversion->GetDexPc(),
2118 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002119 break;
2120
2121 default:
2122 LOG(FATAL) << "Unexpected type conversion from " << input_type
2123 << " to " << result_type;
2124 }
2125 break;
2126
Roland Levillain981e4542014-11-14 11:47:14 +00002127 case Primitive::kPrimChar:
2128 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002129 case Primitive::kPrimBoolean:
2130 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002131 case Primitive::kPrimByte:
2132 case Primitive::kPrimShort:
2133 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002134 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002135 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002136 break;
2137
2138 default:
2139 LOG(FATAL) << "Unexpected type conversion from " << input_type
2140 << " to " << result_type;
2141 }
2142 break;
2143
Roland Levillaindff1f282014-11-05 14:15:05 +00002144 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002145 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002146 case Primitive::kPrimBoolean:
2147 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002148 case Primitive::kPrimByte:
2149 case Primitive::kPrimShort:
2150 case Primitive::kPrimInt:
2151 case Primitive::kPrimChar: {
2152 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002153 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2154 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002155 break;
2156 }
2157
Roland Levillain5b3ee562015-04-14 16:02:41 +01002158 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002159 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002160 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2161 conversion,
2162 conversion->GetDexPc(),
2163 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002164 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002165
Roland Levillaincff13742014-11-17 14:32:17 +00002166 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002167 // Processing a Dex `double-to-float' instruction.
2168 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2169 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002170 break;
2171
2172 default:
2173 LOG(FATAL) << "Unexpected type conversion from " << input_type
2174 << " to " << result_type;
2175 };
2176 break;
2177
Roland Levillaindff1f282014-11-05 14:15:05 +00002178 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002179 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002180 case Primitive::kPrimBoolean:
2181 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002182 case Primitive::kPrimByte:
2183 case Primitive::kPrimShort:
2184 case Primitive::kPrimInt:
2185 case Primitive::kPrimChar: {
2186 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002187 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002188 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2189 out.AsFpuRegisterPairLow<SRegister>());
2190 break;
2191 }
2192
Roland Levillain647b9ed2014-11-27 12:06:00 +00002193 case Primitive::kPrimLong: {
2194 // Processing a Dex `long-to-double' instruction.
2195 Register low = in.AsRegisterPairLow<Register>();
2196 Register high = in.AsRegisterPairHigh<Register>();
2197 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2198 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002199 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002200 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002201 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2202 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002203
Roland Levillain682393c2015-04-14 15:57:52 +01002204 // temp_d = int-to-double(high)
2205 __ vmovsr(temp_s, high);
2206 __ vcvtdi(temp_d, temp_s);
2207 // constant_d = k2Pow32EncodingForDouble
2208 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2209 // out_d = unsigned-to-double(low)
2210 __ vmovsr(out_s, low);
2211 __ vcvtdu(out_d, out_s);
2212 // out_d += temp_d * constant_d
2213 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002214 break;
2215 }
2216
Roland Levillaincff13742014-11-17 14:32:17 +00002217 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002218 // Processing a Dex `float-to-double' instruction.
2219 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2220 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002221 break;
2222
2223 default:
2224 LOG(FATAL) << "Unexpected type conversion from " << input_type
2225 << " to " << result_type;
2226 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002227 break;
2228
2229 default:
2230 LOG(FATAL) << "Unexpected type conversion from " << input_type
2231 << " to " << result_type;
2232 }
2233}
2234
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002235void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002236 LocationSummary* locations =
2237 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002238 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002239 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002240 locations->SetInAt(0, Location::RequiresRegister());
2241 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002242 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2243 break;
2244 }
2245
2246 case Primitive::kPrimLong: {
2247 locations->SetInAt(0, Location::RequiresRegister());
2248 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002249 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002250 break;
2251 }
2252
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002253 case Primitive::kPrimFloat:
2254 case Primitive::kPrimDouble: {
2255 locations->SetInAt(0, Location::RequiresFpuRegister());
2256 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002257 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002258 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002259 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002260
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002261 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002262 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002263 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002264}
2265
2266void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2267 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002268 Location out = locations->Out();
2269 Location first = locations->InAt(0);
2270 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002271 switch (add->GetResultType()) {
2272 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002273 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002274 __ add(out.AsRegister<Register>(),
2275 first.AsRegister<Register>(),
2276 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002277 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002278 __ AddConstant(out.AsRegister<Register>(),
2279 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002280 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002281 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002282 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002283
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002284 case Primitive::kPrimLong: {
2285 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002286 __ adds(out.AsRegisterPairLow<Register>(),
2287 first.AsRegisterPairLow<Register>(),
2288 ShifterOperand(second.AsRegisterPairLow<Register>()));
2289 __ adc(out.AsRegisterPairHigh<Register>(),
2290 first.AsRegisterPairHigh<Register>(),
2291 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002292 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002293 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002294
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002295 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002296 __ vadds(out.AsFpuRegister<SRegister>(),
2297 first.AsFpuRegister<SRegister>(),
2298 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002299 break;
2300
2301 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002302 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2303 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2304 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002305 break;
2306
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002307 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002308 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002309 }
2310}
2311
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002312void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002313 LocationSummary* locations =
2314 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002315 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002316 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002317 locations->SetInAt(0, Location::RequiresRegister());
2318 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002319 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2320 break;
2321 }
2322
2323 case Primitive::kPrimLong: {
2324 locations->SetInAt(0, Location::RequiresRegister());
2325 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002326 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002327 break;
2328 }
Calin Juravle11351682014-10-23 15:38:15 +01002329 case Primitive::kPrimFloat:
2330 case Primitive::kPrimDouble: {
2331 locations->SetInAt(0, Location::RequiresFpuRegister());
2332 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002333 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002334 break;
Calin Juravle11351682014-10-23 15:38:15 +01002335 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002336 default:
Calin Juravle11351682014-10-23 15:38:15 +01002337 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002338 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002339}
2340
2341void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2342 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002343 Location out = locations->Out();
2344 Location first = locations->InAt(0);
2345 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002346 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002347 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002348 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002349 __ sub(out.AsRegister<Register>(),
2350 first.AsRegister<Register>(),
2351 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002352 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002353 __ AddConstant(out.AsRegister<Register>(),
2354 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002355 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002356 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002357 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002358 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002359
Calin Juravle11351682014-10-23 15:38:15 +01002360 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002361 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002362 __ subs(out.AsRegisterPairLow<Register>(),
2363 first.AsRegisterPairLow<Register>(),
2364 ShifterOperand(second.AsRegisterPairLow<Register>()));
2365 __ sbc(out.AsRegisterPairHigh<Register>(),
2366 first.AsRegisterPairHigh<Register>(),
2367 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002368 break;
Calin Juravle11351682014-10-23 15:38:15 +01002369 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002370
Calin Juravle11351682014-10-23 15:38:15 +01002371 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002372 __ vsubs(out.AsFpuRegister<SRegister>(),
2373 first.AsFpuRegister<SRegister>(),
2374 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002375 break;
Calin Juravle11351682014-10-23 15:38:15 +01002376 }
2377
2378 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002379 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2380 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2381 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002382 break;
2383 }
2384
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002385
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002386 default:
Calin Juravle11351682014-10-23 15:38:15 +01002387 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002388 }
2389}
2390
Calin Juravle34bacdf2014-10-07 20:23:36 +01002391void LocationsBuilderARM::VisitMul(HMul* mul) {
2392 LocationSummary* locations =
2393 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2394 switch (mul->GetResultType()) {
2395 case Primitive::kPrimInt:
2396 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002397 locations->SetInAt(0, Location::RequiresRegister());
2398 locations->SetInAt(1, Location::RequiresRegister());
2399 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002400 break;
2401 }
2402
Calin Juravleb5bfa962014-10-21 18:02:24 +01002403 case Primitive::kPrimFloat:
2404 case Primitive::kPrimDouble: {
2405 locations->SetInAt(0, Location::RequiresFpuRegister());
2406 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002407 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002408 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002409 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002410
2411 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002412 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002413 }
2414}
2415
2416void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2417 LocationSummary* locations = mul->GetLocations();
2418 Location out = locations->Out();
2419 Location first = locations->InAt(0);
2420 Location second = locations->InAt(1);
2421 switch (mul->GetResultType()) {
2422 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002423 __ mul(out.AsRegister<Register>(),
2424 first.AsRegister<Register>(),
2425 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002426 break;
2427 }
2428 case Primitive::kPrimLong: {
2429 Register out_hi = out.AsRegisterPairHigh<Register>();
2430 Register out_lo = out.AsRegisterPairLow<Register>();
2431 Register in1_hi = first.AsRegisterPairHigh<Register>();
2432 Register in1_lo = first.AsRegisterPairLow<Register>();
2433 Register in2_hi = second.AsRegisterPairHigh<Register>();
2434 Register in2_lo = second.AsRegisterPairLow<Register>();
2435
2436 // Extra checks to protect caused by the existence of R1_R2.
2437 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2438 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2439 DCHECK_NE(out_hi, in1_lo);
2440 DCHECK_NE(out_hi, in2_lo);
2441
2442 // input: in1 - 64 bits, in2 - 64 bits
2443 // output: out
2444 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2445 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2446 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2447
2448 // IP <- in1.lo * in2.hi
2449 __ mul(IP, in1_lo, in2_hi);
2450 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2451 __ mla(out_hi, in1_hi, in2_lo, IP);
2452 // out.lo <- (in1.lo * in2.lo)[31:0];
2453 __ umull(out_lo, IP, in1_lo, in2_lo);
2454 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2455 __ add(out_hi, out_hi, ShifterOperand(IP));
2456 break;
2457 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002458
2459 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002460 __ vmuls(out.AsFpuRegister<SRegister>(),
2461 first.AsFpuRegister<SRegister>(),
2462 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002463 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002464 }
2465
2466 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002467 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2468 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2469 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002470 break;
2471 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002472
2473 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002474 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002475 }
2476}
2477
Zheng Xuc6667102015-05-15 16:08:45 +08002478void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2479 DCHECK(instruction->IsDiv() || instruction->IsRem());
2480 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2481
2482 LocationSummary* locations = instruction->GetLocations();
2483 Location second = locations->InAt(1);
2484 DCHECK(second.IsConstant());
2485
2486 Register out = locations->Out().AsRegister<Register>();
2487 Register dividend = locations->InAt(0).AsRegister<Register>();
2488 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2489 DCHECK(imm == 1 || imm == -1);
2490
2491 if (instruction->IsRem()) {
2492 __ LoadImmediate(out, 0);
2493 } else {
2494 if (imm == 1) {
2495 __ Mov(out, dividend);
2496 } else {
2497 __ rsb(out, dividend, ShifterOperand(0));
2498 }
2499 }
2500}
2501
2502void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2503 DCHECK(instruction->IsDiv() || instruction->IsRem());
2504 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2505
2506 LocationSummary* locations = instruction->GetLocations();
2507 Location second = locations->InAt(1);
2508 DCHECK(second.IsConstant());
2509
2510 Register out = locations->Out().AsRegister<Register>();
2511 Register dividend = locations->InAt(0).AsRegister<Register>();
2512 Register temp = locations->GetTemp(0).AsRegister<Register>();
2513 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002514 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002515 DCHECK(IsPowerOfTwo(abs_imm));
2516 int ctz_imm = CTZ(abs_imm);
2517
2518 if (ctz_imm == 1) {
2519 __ Lsr(temp, dividend, 32 - ctz_imm);
2520 } else {
2521 __ Asr(temp, dividend, 31);
2522 __ Lsr(temp, temp, 32 - ctz_imm);
2523 }
2524 __ add(out, temp, ShifterOperand(dividend));
2525
2526 if (instruction->IsDiv()) {
2527 __ Asr(out, out, ctz_imm);
2528 if (imm < 0) {
2529 __ rsb(out, out, ShifterOperand(0));
2530 }
2531 } else {
2532 __ ubfx(out, out, 0, ctz_imm);
2533 __ sub(out, out, ShifterOperand(temp));
2534 }
2535}
2536
2537void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2538 DCHECK(instruction->IsDiv() || instruction->IsRem());
2539 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2540
2541 LocationSummary* locations = instruction->GetLocations();
2542 Location second = locations->InAt(1);
2543 DCHECK(second.IsConstant());
2544
2545 Register out = locations->Out().AsRegister<Register>();
2546 Register dividend = locations->InAt(0).AsRegister<Register>();
2547 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2548 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2549 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2550
2551 int64_t magic;
2552 int shift;
2553 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2554
2555 __ LoadImmediate(temp1, magic);
2556 __ smull(temp2, temp1, dividend, temp1);
2557
2558 if (imm > 0 && magic < 0) {
2559 __ add(temp1, temp1, ShifterOperand(dividend));
2560 } else if (imm < 0 && magic > 0) {
2561 __ sub(temp1, temp1, ShifterOperand(dividend));
2562 }
2563
2564 if (shift != 0) {
2565 __ Asr(temp1, temp1, shift);
2566 }
2567
2568 if (instruction->IsDiv()) {
2569 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2570 } else {
2571 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2572 // TODO: Strength reduction for mls.
2573 __ LoadImmediate(temp2, imm);
2574 __ mls(out, temp1, temp2, dividend);
2575 }
2576}
2577
2578void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2579 DCHECK(instruction->IsDiv() || instruction->IsRem());
2580 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2581
2582 LocationSummary* locations = instruction->GetLocations();
2583 Location second = locations->InAt(1);
2584 DCHECK(second.IsConstant());
2585
2586 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2587 if (imm == 0) {
2588 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2589 } else if (imm == 1 || imm == -1) {
2590 DivRemOneOrMinusOne(instruction);
2591 } else if (IsPowerOfTwo(std::abs(imm))) {
2592 DivRemByPowerOfTwo(instruction);
2593 } else {
2594 DCHECK(imm <= -2 || imm >= 2);
2595 GenerateDivRemWithAnyConstant(instruction);
2596 }
2597}
2598
Calin Juravle7c4954d2014-10-28 16:57:40 +00002599void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002600 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2601 if (div->GetResultType() == Primitive::kPrimLong) {
2602 // pLdiv runtime call.
2603 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002604 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2605 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002606 } else if (div->GetResultType() == Primitive::kPrimInt &&
2607 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2608 // pIdivmod runtime call.
2609 call_kind = LocationSummary::kCall;
2610 }
2611
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002612 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2613
Calin Juravle7c4954d2014-10-28 16:57:40 +00002614 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002615 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002616 if (div->InputAt(1)->IsConstant()) {
2617 locations->SetInAt(0, Location::RequiresRegister());
2618 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2619 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2620 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2621 if (abs_imm <= 1) {
2622 // No temp register required.
2623 } else {
2624 locations->AddTemp(Location::RequiresRegister());
2625 if (!IsPowerOfTwo(abs_imm)) {
2626 locations->AddTemp(Location::RequiresRegister());
2627 }
2628 }
2629 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002630 locations->SetInAt(0, Location::RequiresRegister());
2631 locations->SetInAt(1, Location::RequiresRegister());
2632 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2633 } else {
2634 InvokeRuntimeCallingConvention calling_convention;
2635 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2636 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2637 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2638 // we only need the former.
2639 locations->SetOut(Location::RegisterLocation(R0));
2640 }
Calin Juravled0d48522014-11-04 16:40:20 +00002641 break;
2642 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002643 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002644 InvokeRuntimeCallingConvention calling_convention;
2645 locations->SetInAt(0, Location::RegisterPairLocation(
2646 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2647 locations->SetInAt(1, Location::RegisterPairLocation(
2648 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002649 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002650 break;
2651 }
2652 case Primitive::kPrimFloat:
2653 case Primitive::kPrimDouble: {
2654 locations->SetInAt(0, Location::RequiresFpuRegister());
2655 locations->SetInAt(1, Location::RequiresFpuRegister());
2656 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2657 break;
2658 }
2659
2660 default:
2661 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2662 }
2663}
2664
2665void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2666 LocationSummary* locations = div->GetLocations();
2667 Location out = locations->Out();
2668 Location first = locations->InAt(0);
2669 Location second = locations->InAt(1);
2670
2671 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002672 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002673 if (second.IsConstant()) {
2674 GenerateDivRemConstantIntegral(div);
2675 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002676 __ sdiv(out.AsRegister<Register>(),
2677 first.AsRegister<Register>(),
2678 second.AsRegister<Register>());
2679 } else {
2680 InvokeRuntimeCallingConvention calling_convention;
2681 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2682 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2683 DCHECK_EQ(R0, out.AsRegister<Register>());
2684
2685 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2686 }
Calin Juravled0d48522014-11-04 16:40:20 +00002687 break;
2688 }
2689
Calin Juravle7c4954d2014-10-28 16:57:40 +00002690 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002691 InvokeRuntimeCallingConvention calling_convention;
2692 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2693 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2694 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2695 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2696 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002697 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002698
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002699 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002700 break;
2701 }
2702
2703 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002704 __ vdivs(out.AsFpuRegister<SRegister>(),
2705 first.AsFpuRegister<SRegister>(),
2706 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002707 break;
2708 }
2709
2710 case Primitive::kPrimDouble: {
2711 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2712 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2713 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2714 break;
2715 }
2716
2717 default:
2718 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2719 }
2720}
2721
Calin Juravlebacfec32014-11-14 15:54:36 +00002722void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002723 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002724
2725 // Most remainders are implemented in the runtime.
2726 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002727 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2728 // sdiv will be replaced by other instruction sequence.
2729 call_kind = LocationSummary::kNoCall;
2730 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2731 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002732 // Have hardware divide instruction for int, do it with three instructions.
2733 call_kind = LocationSummary::kNoCall;
2734 }
2735
Calin Juravlebacfec32014-11-14 15:54:36 +00002736 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2737
Calin Juravled2ec87d2014-12-08 14:24:46 +00002738 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002739 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002740 if (rem->InputAt(1)->IsConstant()) {
2741 locations->SetInAt(0, Location::RequiresRegister());
2742 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2743 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2744 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2745 if (abs_imm <= 1) {
2746 // No temp register required.
2747 } else {
2748 locations->AddTemp(Location::RequiresRegister());
2749 if (!IsPowerOfTwo(abs_imm)) {
2750 locations->AddTemp(Location::RequiresRegister());
2751 }
2752 }
2753 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002754 locations->SetInAt(0, Location::RequiresRegister());
2755 locations->SetInAt(1, Location::RequiresRegister());
2756 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2757 locations->AddTemp(Location::RequiresRegister());
2758 } else {
2759 InvokeRuntimeCallingConvention calling_convention;
2760 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2761 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2762 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2763 // we only need the latter.
2764 locations->SetOut(Location::RegisterLocation(R1));
2765 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002766 break;
2767 }
2768 case Primitive::kPrimLong: {
2769 InvokeRuntimeCallingConvention calling_convention;
2770 locations->SetInAt(0, Location::RegisterPairLocation(
2771 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2772 locations->SetInAt(1, Location::RegisterPairLocation(
2773 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2774 // The runtime helper puts the output in R2,R3.
2775 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2776 break;
2777 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002778 case Primitive::kPrimFloat: {
2779 InvokeRuntimeCallingConvention calling_convention;
2780 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2781 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2782 locations->SetOut(Location::FpuRegisterLocation(S0));
2783 break;
2784 }
2785
Calin Juravlebacfec32014-11-14 15:54:36 +00002786 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002787 InvokeRuntimeCallingConvention calling_convention;
2788 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2789 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2790 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2791 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2792 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002793 break;
2794 }
2795
2796 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002797 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002798 }
2799}
2800
2801void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2802 LocationSummary* locations = rem->GetLocations();
2803 Location out = locations->Out();
2804 Location first = locations->InAt(0);
2805 Location second = locations->InAt(1);
2806
Calin Juravled2ec87d2014-12-08 14:24:46 +00002807 Primitive::Type type = rem->GetResultType();
2808 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002809 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002810 if (second.IsConstant()) {
2811 GenerateDivRemConstantIntegral(rem);
2812 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002813 Register reg1 = first.AsRegister<Register>();
2814 Register reg2 = second.AsRegister<Register>();
2815 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002816
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002817 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002818 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002819 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002820 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002821 } else {
2822 InvokeRuntimeCallingConvention calling_convention;
2823 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2824 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2825 DCHECK_EQ(R1, out.AsRegister<Register>());
2826
2827 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2828 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002829 break;
2830 }
2831
2832 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002833 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002834 break;
2835 }
2836
Calin Juravled2ec87d2014-12-08 14:24:46 +00002837 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002838 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002839 break;
2840 }
2841
Calin Juravlebacfec32014-11-14 15:54:36 +00002842 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002843 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002844 break;
2845 }
2846
2847 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002848 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002849 }
2850}
2851
Calin Juravled0d48522014-11-04 16:40:20 +00002852void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00002853 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2854 ? LocationSummary::kCallOnSlowPath
2855 : LocationSummary::kNoCall;
2856 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002857 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002858 if (instruction->HasUses()) {
2859 locations->SetOut(Location::SameAsFirstInput());
2860 }
2861}
2862
2863void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002864 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00002865 codegen_->AddSlowPath(slow_path);
2866
2867 LocationSummary* locations = instruction->GetLocations();
2868 Location value = locations->InAt(0);
2869
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002870 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002871 case Primitive::kPrimByte:
2872 case Primitive::kPrimChar:
2873 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002874 case Primitive::kPrimInt: {
2875 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002876 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002877 } else {
2878 DCHECK(value.IsConstant()) << value;
2879 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2880 __ b(slow_path->GetEntryLabel());
2881 }
2882 }
2883 break;
2884 }
2885 case Primitive::kPrimLong: {
2886 if (value.IsRegisterPair()) {
2887 __ orrs(IP,
2888 value.AsRegisterPairLow<Register>(),
2889 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2890 __ b(slow_path->GetEntryLabel(), EQ);
2891 } else {
2892 DCHECK(value.IsConstant()) << value;
2893 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2894 __ b(slow_path->GetEntryLabel());
2895 }
2896 }
2897 break;
2898 default:
2899 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2900 }
2901 }
Calin Juravled0d48522014-11-04 16:40:20 +00002902}
2903
Calin Juravle9aec02f2014-11-18 23:06:35 +00002904void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2905 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2906
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002907 LocationSummary* locations =
2908 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002909
2910 switch (op->GetResultType()) {
2911 case Primitive::kPrimInt: {
2912 locations->SetInAt(0, Location::RequiresRegister());
2913 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002914 // Make the output overlap, as it will be used to hold the masked
2915 // second input.
2916 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002917 break;
2918 }
2919 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002920 locations->SetInAt(0, Location::RequiresRegister());
2921 locations->SetInAt(1, Location::RequiresRegister());
2922 locations->AddTemp(Location::RequiresRegister());
2923 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002924 break;
2925 }
2926 default:
2927 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2928 }
2929}
2930
2931void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2932 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2933
2934 LocationSummary* locations = op->GetLocations();
2935 Location out = locations->Out();
2936 Location first = locations->InAt(0);
2937 Location second = locations->InAt(1);
2938
2939 Primitive::Type type = op->GetResultType();
2940 switch (type) {
2941 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002942 Register out_reg = out.AsRegister<Register>();
2943 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002944 // Arm doesn't mask the shift count so we need to do it ourselves.
2945 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002946 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002947 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002948 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002949 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002950 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002951 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002952 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002953 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002954 }
2955 } else {
2956 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2957 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2958 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2959 __ Mov(out_reg, first_reg);
2960 } else if (op->IsShl()) {
2961 __ Lsl(out_reg, first_reg, shift_value);
2962 } else if (op->IsShr()) {
2963 __ Asr(out_reg, first_reg, shift_value);
2964 } else {
2965 __ Lsr(out_reg, first_reg, shift_value);
2966 }
2967 }
2968 break;
2969 }
2970 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002971 Register o_h = out.AsRegisterPairHigh<Register>();
2972 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002973
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002974 Register temp = locations->GetTemp(0).AsRegister<Register>();
2975
2976 Register high = first.AsRegisterPairHigh<Register>();
2977 Register low = first.AsRegisterPairLow<Register>();
2978
2979 Register second_reg = second.AsRegister<Register>();
2980
Calin Juravle9aec02f2014-11-18 23:06:35 +00002981 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002982 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002983 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002984 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002985 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002986 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002987 __ Lsr(temp, low, temp);
2988 __ orr(o_h, o_h, ShifterOperand(temp));
2989 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002990 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002991 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002992 __ Lsl(o_h, low, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002993 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002994 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002995 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002996 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002997 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002998 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002999 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003000 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003001 __ Lsl(temp, high, temp);
3002 __ orr(o_l, o_l, ShifterOperand(temp));
3003 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003004 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003005 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003006 __ Asr(o_l, high, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003007 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003008 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003009 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003010 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003011 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003012 __ Lsr(o_l, low, o_h);
3013 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003014 __ Lsl(temp, high, temp);
3015 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003016 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003017 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003018 __ Lsr(o_l, high, temp, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003019 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003020 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003021 break;
3022 }
3023 default:
3024 LOG(FATAL) << "Unexpected operation type " << type;
3025 }
3026}
3027
3028void LocationsBuilderARM::VisitShl(HShl* shl) {
3029 HandleShift(shl);
3030}
3031
3032void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3033 HandleShift(shl);
3034}
3035
3036void LocationsBuilderARM::VisitShr(HShr* shr) {
3037 HandleShift(shr);
3038}
3039
3040void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3041 HandleShift(shr);
3042}
3043
3044void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3045 HandleShift(ushr);
3046}
3047
3048void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3049 HandleShift(ushr);
3050}
3051
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003052void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003053 LocationSummary* locations =
3054 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003055 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003056 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003057 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003058 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003059}
3060
3061void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3062 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003063 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003064 // Note: if heap poisoning is enabled, the entry point takes cares
3065 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003066 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003067 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003068 instruction->GetDexPc(),
3069 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003070}
3071
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003072void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3073 LocationSummary* locations =
3074 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3075 InvokeRuntimeCallingConvention calling_convention;
3076 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003077 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003078 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003079 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003080}
3081
3082void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3083 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003084 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003085 // Note: if heap poisoning is enabled, the entry point takes cares
3086 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003087 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003088 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003089 instruction->GetDexPc(),
3090 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003091}
3092
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003093void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003094 LocationSummary* locations =
3095 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003096 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3097 if (location.IsStackSlot()) {
3098 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3099 } else if (location.IsDoubleStackSlot()) {
3100 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003101 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003102 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003103}
3104
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003105void InstructionCodeGeneratorARM::VisitParameterValue(
3106 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003107 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003108}
3109
3110void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3111 LocationSummary* locations =
3112 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3113 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3114}
3115
3116void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3117 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003118}
3119
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003120void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003121 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003122 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003123 locations->SetInAt(0, Location::RequiresRegister());
3124 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003125}
3126
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003127void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3128 LocationSummary* locations = not_->GetLocations();
3129 Location out = locations->Out();
3130 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003131 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003132 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003133 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003134 break;
3135
3136 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003137 __ mvn(out.AsRegisterPairLow<Register>(),
3138 ShifterOperand(in.AsRegisterPairLow<Register>()));
3139 __ mvn(out.AsRegisterPairHigh<Register>(),
3140 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003141 break;
3142
3143 default:
3144 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3145 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003146}
3147
David Brazdil66d126e2015-04-03 16:02:44 +01003148void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3149 LocationSummary* locations =
3150 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3151 locations->SetInAt(0, Location::RequiresRegister());
3152 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3153}
3154
3155void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003156 LocationSummary* locations = bool_not->GetLocations();
3157 Location out = locations->Out();
3158 Location in = locations->InAt(0);
3159 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3160}
3161
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003162void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003163 LocationSummary* locations =
3164 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003165 switch (compare->InputAt(0)->GetType()) {
3166 case Primitive::kPrimLong: {
3167 locations->SetInAt(0, Location::RequiresRegister());
3168 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003169 // Output overlaps because it is written before doing the low comparison.
3170 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003171 break;
3172 }
3173 case Primitive::kPrimFloat:
3174 case Primitive::kPrimDouble: {
3175 locations->SetInAt(0, Location::RequiresFpuRegister());
3176 locations->SetInAt(1, Location::RequiresFpuRegister());
3177 locations->SetOut(Location::RequiresRegister());
3178 break;
3179 }
3180 default:
3181 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3182 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003183}
3184
3185void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003186 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003187 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003188 Location left = locations->InAt(0);
3189 Location right = locations->InAt(1);
3190
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003191 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003192 Primitive::Type type = compare->InputAt(0)->GetType();
3193 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003194 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003195 __ cmp(left.AsRegisterPairHigh<Register>(),
3196 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003197 __ b(&less, LT);
3198 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003199 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003200 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003201 __ cmp(left.AsRegisterPairLow<Register>(),
3202 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003203 break;
3204 }
3205 case Primitive::kPrimFloat:
3206 case Primitive::kPrimDouble: {
3207 __ LoadImmediate(out, 0);
3208 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003209 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003210 } else {
3211 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3212 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3213 }
3214 __ vmstat(); // transfer FP status register to ARM APSR.
3215 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003216 break;
3217 }
3218 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003219 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003220 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003221 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003222 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003223
3224 __ Bind(&greater);
3225 __ LoadImmediate(out, 1);
3226 __ b(&done);
3227
3228 __ Bind(&less);
3229 __ LoadImmediate(out, -1);
3230
3231 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003232}
3233
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003234void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003235 LocationSummary* locations =
3236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003237 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3238 locations->SetInAt(i, Location::Any());
3239 }
3240 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003241}
3242
3243void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003244 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003245 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003246}
3247
Calin Juravle52c48962014-12-16 17:02:57 +00003248void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3249 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003250 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003251 switch (kind) {
3252 case MemBarrierKind::kAnyStore:
3253 case MemBarrierKind::kLoadAny:
3254 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003255 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003256 break;
3257 }
3258 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003259 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003260 break;
3261 }
3262 default:
3263 LOG(FATAL) << "Unexpected memory barrier " << kind;
3264 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003265 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003266}
3267
3268void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3269 uint32_t offset,
3270 Register out_lo,
3271 Register out_hi) {
3272 if (offset != 0) {
3273 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003274 __ add(IP, addr, ShifterOperand(out_lo));
3275 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003276 }
3277 __ ldrexd(out_lo, out_hi, addr);
3278}
3279
3280void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3281 uint32_t offset,
3282 Register value_lo,
3283 Register value_hi,
3284 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003285 Register temp2,
3286 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003287 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003288 if (offset != 0) {
3289 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003290 __ add(IP, addr, ShifterOperand(temp1));
3291 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003292 }
3293 __ Bind(&fail);
3294 // We need a load followed by store. (The address used in a STREX instruction must
3295 // be the same as the address in the most recently executed LDREX instruction.)
3296 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003297 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003298 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003299 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003300}
3301
3302void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3303 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3304
Nicolas Geoffray39468442014-09-02 15:17:15 +01003305 LocationSummary* locations =
3306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003307 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003308
Calin Juravle52c48962014-12-16 17:02:57 +00003309 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003310 if (Primitive::IsFloatingPointType(field_type)) {
3311 locations->SetInAt(1, Location::RequiresFpuRegister());
3312 } else {
3313 locations->SetInAt(1, Location::RequiresRegister());
3314 }
3315
Calin Juravle52c48962014-12-16 17:02:57 +00003316 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003317 bool generate_volatile = field_info.IsVolatile()
3318 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003319 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003320 bool needs_write_barrier =
3321 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003322 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003323 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003324 if (needs_write_barrier) {
3325 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003326 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003327 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003328 // Arm encoding have some additional constraints for ldrexd/strexd:
3329 // - registers need to be consecutive
3330 // - the first register should be even but not R14.
3331 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3332 // enable Arm encoding.
3333 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3334
3335 locations->AddTemp(Location::RequiresRegister());
3336 locations->AddTemp(Location::RequiresRegister());
3337 if (field_type == Primitive::kPrimDouble) {
3338 // For doubles we need two more registers to copy the value.
3339 locations->AddTemp(Location::RegisterLocation(R2));
3340 locations->AddTemp(Location::RegisterLocation(R3));
3341 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003342 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003343}
3344
Calin Juravle52c48962014-12-16 17:02:57 +00003345void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003346 const FieldInfo& field_info,
3347 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003348 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3349
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003350 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003351 Register base = locations->InAt(0).AsRegister<Register>();
3352 Location value = locations->InAt(1);
3353
3354 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003355 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003356 Primitive::Type field_type = field_info.GetFieldType();
3357 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003358 bool needs_write_barrier =
3359 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003360
3361 if (is_volatile) {
3362 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3363 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003364
3365 switch (field_type) {
3366 case Primitive::kPrimBoolean:
3367 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003368 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003369 break;
3370 }
3371
3372 case Primitive::kPrimShort:
3373 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003374 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003375 break;
3376 }
3377
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003378 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003379 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003380 if (kPoisonHeapReferences && needs_write_barrier) {
3381 // Note that in the case where `value` is a null reference,
3382 // we do not enter this block, as a null reference does not
3383 // need poisoning.
3384 DCHECK_EQ(field_type, Primitive::kPrimNot);
3385 Register temp = locations->GetTemp(0).AsRegister<Register>();
3386 __ Mov(temp, value.AsRegister<Register>());
3387 __ PoisonHeapReference(temp);
3388 __ StoreToOffset(kStoreWord, temp, base, offset);
3389 } else {
3390 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3391 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003392 break;
3393 }
3394
3395 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003396 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003397 GenerateWideAtomicStore(base, offset,
3398 value.AsRegisterPairLow<Register>(),
3399 value.AsRegisterPairHigh<Register>(),
3400 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003401 locations->GetTemp(1).AsRegister<Register>(),
3402 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003403 } else {
3404 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003405 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003406 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003407 break;
3408 }
3409
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003410 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003411 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003412 break;
3413 }
3414
3415 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003416 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003417 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003418 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3419 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3420
3421 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3422
3423 GenerateWideAtomicStore(base, offset,
3424 value_reg_lo,
3425 value_reg_hi,
3426 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003427 locations->GetTemp(3).AsRegister<Register>(),
3428 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003429 } else {
3430 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003431 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003432 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003433 break;
3434 }
3435
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003436 case Primitive::kPrimVoid:
3437 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003438 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003439 }
Calin Juravle52c48962014-12-16 17:02:57 +00003440
Calin Juravle77520bc2015-01-12 18:45:46 +00003441 // Longs and doubles are handled in the switch.
3442 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3443 codegen_->MaybeRecordImplicitNullCheck(instruction);
3444 }
3445
3446 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3447 Register temp = locations->GetTemp(0).AsRegister<Register>();
3448 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003449 codegen_->MarkGCCard(
3450 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003451 }
3452
Calin Juravle52c48962014-12-16 17:02:57 +00003453 if (is_volatile) {
3454 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3455 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003456}
3457
Calin Juravle52c48962014-12-16 17:02:57 +00003458void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3459 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003460 LocationSummary* locations =
3461 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003462 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003463
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003464 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003465 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003466 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003467 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003468
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003469 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3470 locations->SetOut(Location::RequiresFpuRegister());
3471 } else {
3472 locations->SetOut(Location::RequiresRegister(),
3473 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3474 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003475 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003476 // Arm encoding have some additional constraints for ldrexd/strexd:
3477 // - registers need to be consecutive
3478 // - the first register should be even but not R14.
3479 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3480 // enable Arm encoding.
3481 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3482 locations->AddTemp(Location::RequiresRegister());
3483 locations->AddTemp(Location::RequiresRegister());
3484 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003485}
3486
Calin Juravle52c48962014-12-16 17:02:57 +00003487void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3488 const FieldInfo& field_info) {
3489 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003490
Calin Juravle52c48962014-12-16 17:02:57 +00003491 LocationSummary* locations = instruction->GetLocations();
3492 Register base = locations->InAt(0).AsRegister<Register>();
3493 Location out = locations->Out();
3494 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003495 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003496 Primitive::Type field_type = field_info.GetFieldType();
3497 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3498
3499 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003500 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003501 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003502 break;
3503 }
3504
3505 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003506 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003507 break;
3508 }
3509
3510 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003511 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003512 break;
3513 }
3514
3515 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003516 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003517 break;
3518 }
3519
3520 case Primitive::kPrimInt:
3521 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003522 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003523 break;
3524 }
3525
3526 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003527 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003528 GenerateWideAtomicLoad(base, offset,
3529 out.AsRegisterPairLow<Register>(),
3530 out.AsRegisterPairHigh<Register>());
3531 } else {
3532 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3533 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003534 break;
3535 }
3536
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003537 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003538 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003539 break;
3540 }
3541
3542 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003543 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003544 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003545 Register lo = locations->GetTemp(0).AsRegister<Register>();
3546 Register hi = locations->GetTemp(1).AsRegister<Register>();
3547 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003548 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003549 __ vmovdrr(out_reg, lo, hi);
3550 } else {
3551 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003552 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003553 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003554 break;
3555 }
3556
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003557 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003558 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003559 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003560 }
Calin Juravle52c48962014-12-16 17:02:57 +00003561
Calin Juravle77520bc2015-01-12 18:45:46 +00003562 // Doubles are handled in the switch.
3563 if (field_type != Primitive::kPrimDouble) {
3564 codegen_->MaybeRecordImplicitNullCheck(instruction);
3565 }
3566
Calin Juravle52c48962014-12-16 17:02:57 +00003567 if (is_volatile) {
3568 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3569 }
Roland Levillain4d027112015-07-01 15:41:14 +01003570
3571 if (field_type == Primitive::kPrimNot) {
3572 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3573 }
Calin Juravle52c48962014-12-16 17:02:57 +00003574}
3575
3576void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3577 HandleFieldSet(instruction, instruction->GetFieldInfo());
3578}
3579
3580void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003581 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003582}
3583
3584void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3585 HandleFieldGet(instruction, instruction->GetFieldInfo());
3586}
3587
3588void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3589 HandleFieldGet(instruction, instruction->GetFieldInfo());
3590}
3591
3592void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3593 HandleFieldGet(instruction, instruction->GetFieldInfo());
3594}
3595
3596void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3597 HandleFieldGet(instruction, instruction->GetFieldInfo());
3598}
3599
3600void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3601 HandleFieldSet(instruction, instruction->GetFieldInfo());
3602}
3603
3604void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003605 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003606}
3607
3608void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003609 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3610 ? LocationSummary::kCallOnSlowPath
3611 : LocationSummary::kNoCall;
3612 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003613 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003614 if (instruction->HasUses()) {
3615 locations->SetOut(Location::SameAsFirstInput());
3616 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003617}
3618
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003619void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003620 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3621 return;
3622 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003623 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003624
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003625 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3626 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3627}
3628
3629void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003630 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003631 codegen_->AddSlowPath(slow_path);
3632
3633 LocationSummary* locations = instruction->GetLocations();
3634 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003635
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003636 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003637}
3638
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003639void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003640 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003641 GenerateImplicitNullCheck(instruction);
3642 } else {
3643 GenerateExplicitNullCheck(instruction);
3644 }
3645}
3646
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003647void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003648 LocationSummary* locations =
3649 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003650 locations->SetInAt(0, Location::RequiresRegister());
3651 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003652 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3653 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3654 } else {
3655 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3656 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003657}
3658
3659void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3660 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003662 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003663 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003664
Roland Levillain4d027112015-07-01 15:41:14 +01003665 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003666 case Primitive::kPrimBoolean: {
3667 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003668 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003669 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003670 size_t offset =
3671 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003672 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3673 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003674 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003675 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3676 }
3677 break;
3678 }
3679
3680 case Primitive::kPrimByte: {
3681 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003682 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003683 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003684 size_t offset =
3685 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003686 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3687 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003688 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003689 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3690 }
3691 break;
3692 }
3693
3694 case Primitive::kPrimShort: {
3695 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003696 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003697 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003698 size_t offset =
3699 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003700 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3701 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003702 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003703 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3704 }
3705 break;
3706 }
3707
3708 case Primitive::kPrimChar: {
3709 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003710 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003711 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003712 size_t offset =
3713 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003714 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3715 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003716 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3718 }
3719 break;
3720 }
3721
3722 case Primitive::kPrimInt:
3723 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003724 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3725 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003726 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003727 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003728 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003729 size_t offset =
3730 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003731 __ LoadFromOffset(kLoadWord, out, obj, offset);
3732 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003733 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003734 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3735 }
3736 break;
3737 }
3738
3739 case Primitive::kPrimLong: {
3740 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003741 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003742 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003743 size_t offset =
3744 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003745 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003746 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003747 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003748 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003749 }
3750 break;
3751 }
3752
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003753 case Primitive::kPrimFloat: {
3754 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3755 Location out = locations->Out();
3756 DCHECK(out.IsFpuRegister());
3757 if (index.IsConstant()) {
3758 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3759 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3760 } else {
3761 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3762 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3763 }
3764 break;
3765 }
3766
3767 case Primitive::kPrimDouble: {
3768 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3769 Location out = locations->Out();
3770 DCHECK(out.IsFpuRegisterPair());
3771 if (index.IsConstant()) {
3772 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3773 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3774 } else {
3775 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3776 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3777 }
3778 break;
3779 }
3780
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003781 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003782 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003783 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003784 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003785 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003786
3787 if (type == Primitive::kPrimNot) {
3788 Register out = locations->Out().AsRegister<Register>();
3789 __ MaybeUnpoisonHeapReference(out);
3790 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003791}
3792
3793void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003794 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003795
3796 bool needs_write_barrier =
3797 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003798 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003799
Nicolas Geoffray39468442014-09-02 15:17:15 +01003800 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003801 instruction,
3802 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
3803 locations->SetInAt(0, Location::RequiresRegister());
3804 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3805 if (Primitive::IsFloatingPointType(value_type)) {
3806 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003807 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003808 locations->SetInAt(2, Location::RequiresRegister());
3809 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003810
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003811 if (needs_write_barrier) {
3812 // Temporary registers for the write barrier.
3813 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
3814 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003815 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003816}
3817
3818void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3819 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003820 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003821 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003822 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003823 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003824 bool needs_write_barrier =
3825 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003826
3827 switch (value_type) {
3828 case Primitive::kPrimBoolean:
3829 case Primitive::kPrimByte: {
3830 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003831 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003832 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003833 size_t offset =
3834 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003835 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003836 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003837 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003838 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3839 }
3840 break;
3841 }
3842
3843 case Primitive::kPrimShort:
3844 case Primitive::kPrimChar: {
3845 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003846 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003847 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003848 size_t offset =
3849 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003850 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003851 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003852 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003853 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3854 }
3855 break;
3856 }
3857
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003858 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003859 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3860 Register value = locations->InAt(2).AsRegister<Register>();
3861 Register source = value;
3862
3863 if (instruction->InputAt(2)->IsNullConstant()) {
3864 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003865 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003866 size_t offset =
3867 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003868 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003869 } else {
3870 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003871 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003872 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003873 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003874 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003875 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003876
3877 DCHECK(needs_write_barrier);
3878 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
3879 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
3880 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3881 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3882 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3883 Label done;
3884 SlowPathCode* slow_path = nullptr;
3885
3886 if (may_need_runtime_call) {
3887 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
3888 codegen_->AddSlowPath(slow_path);
3889 if (instruction->GetValueCanBeNull()) {
3890 Label non_zero;
3891 __ CompareAndBranchIfNonZero(value, &non_zero);
3892 if (index.IsConstant()) {
3893 size_t offset =
3894 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3895 __ StoreToOffset(kStoreWord, value, array, offset);
3896 } else {
3897 DCHECK(index.IsRegister()) << index;
3898 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3899 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3900 }
3901 codegen_->MaybeRecordImplicitNullCheck(instruction);
3902 __ b(&done);
3903 __ Bind(&non_zero);
3904 }
3905
3906 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
3907 codegen_->MaybeRecordImplicitNullCheck(instruction);
3908 __ MaybeUnpoisonHeapReference(temp1);
3909 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
3910 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
3911 // No need to poison/unpoison, we're comparing two poisoined references.
3912 __ cmp(temp1, ShifterOperand(temp2));
3913 if (instruction->StaticTypeOfArrayIsObjectArray()) {
3914 Label do_put;
3915 __ b(&do_put, EQ);
3916 __ MaybeUnpoisonHeapReference(temp1);
3917 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
3918 // No need to poison/unpoison, we're comparing against null.
3919 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
3920 __ Bind(&do_put);
3921 } else {
3922 __ b(slow_path->GetEntryLabel(), NE);
3923 }
3924 }
3925
3926 if (kPoisonHeapReferences) {
3927 // Note that in the case where `value` is a null reference,
3928 // we do not enter this block, as a null reference does not
3929 // need poisoning.
3930 DCHECK_EQ(value_type, Primitive::kPrimNot);
3931 __ Mov(temp1, value);
3932 __ PoisonHeapReference(temp1);
3933 source = temp1;
3934 }
3935
3936 if (index.IsConstant()) {
3937 size_t offset =
3938 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3939 __ StoreToOffset(kStoreWord, source, array, offset);
3940 } else {
3941 DCHECK(index.IsRegister()) << index;
3942 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3943 __ StoreToOffset(kStoreWord, source, IP, data_offset);
3944 }
3945
3946 if (!may_need_runtime_call) {
3947 codegen_->MaybeRecordImplicitNullCheck(instruction);
3948 }
3949
3950 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
3951
3952 if (done.IsLinked()) {
3953 __ Bind(&done);
3954 }
3955
3956 if (slow_path != nullptr) {
3957 __ Bind(slow_path->GetExitLabel());
3958 }
3959
3960 break;
3961 }
3962
3963 case Primitive::kPrimInt: {
3964 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3965 Register value = locations->InAt(2).AsRegister<Register>();
3966 if (index.IsConstant()) {
3967 size_t offset =
3968 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3969 __ StoreToOffset(kStoreWord, value, array, offset);
3970 } else {
3971 DCHECK(index.IsRegister()) << index;
3972 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3973 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3974 }
3975
3976 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003977 break;
3978 }
3979
3980 case Primitive::kPrimLong: {
3981 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003982 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003983 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003984 size_t offset =
3985 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003986 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003987 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003988 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003989 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003990 }
3991 break;
3992 }
3993
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003994 case Primitive::kPrimFloat: {
3995 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3996 Location value = locations->InAt(2);
3997 DCHECK(value.IsFpuRegister());
3998 if (index.IsConstant()) {
3999 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004000 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004001 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004002 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004003 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4004 }
4005 break;
4006 }
4007
4008 case Primitive::kPrimDouble: {
4009 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4010 Location value = locations->InAt(2);
4011 DCHECK(value.IsFpuRegisterPair());
4012 if (index.IsConstant()) {
4013 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004014 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004015 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004016 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004017 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4018 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004019
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004020 break;
4021 }
4022
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004023 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004024 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004025 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004026 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004027
4028 // Ints and objects are handled in the switch.
4029 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4030 codegen_->MaybeRecordImplicitNullCheck(instruction);
4031 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004032}
4033
4034void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004035 LocationSummary* locations =
4036 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004037 locations->SetInAt(0, Location::RequiresRegister());
4038 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004039}
4040
4041void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4042 LocationSummary* locations = instruction->GetLocations();
4043 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004044 Register obj = locations->InAt(0).AsRegister<Register>();
4045 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004046 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004047 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004048}
4049
4050void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004051 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4052 ? LocationSummary::kCallOnSlowPath
4053 : LocationSummary::kNoCall;
4054 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004055 locations->SetInAt(0, Location::RequiresRegister());
4056 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004057 if (instruction->HasUses()) {
4058 locations->SetOut(Location::SameAsFirstInput());
4059 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004060}
4061
4062void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4063 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004064 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004065 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004066 codegen_->AddSlowPath(slow_path);
4067
Roland Levillain271ab9c2014-11-27 15:23:57 +00004068 Register index = locations->InAt(0).AsRegister<Register>();
4069 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004070
4071 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004072 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004073}
4074
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004075void CodeGeneratorARM::MarkGCCard(Register temp,
4076 Register card,
4077 Register object,
4078 Register value,
4079 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004080 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004081 if (can_be_null) {
4082 __ CompareAndBranchIfZero(value, &is_null);
4083 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004084 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4085 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4086 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004087 if (can_be_null) {
4088 __ Bind(&is_null);
4089 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004090}
4091
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004092void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4093 temp->SetLocations(nullptr);
4094}
4095
4096void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
4097 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004098 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004099}
4100
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004101void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004102 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004103 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004104}
4105
4106void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004107 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4108}
4109
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004110void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4111 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4112}
4113
4114void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004115 HBasicBlock* block = instruction->GetBlock();
4116 if (block->GetLoopInformation() != nullptr) {
4117 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4118 // The back edge will generate the suspend check.
4119 return;
4120 }
4121 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4122 // The goto will generate the suspend check.
4123 return;
4124 }
4125 GenerateSuspendCheck(instruction, nullptr);
4126}
4127
4128void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4129 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004130 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004131 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4132 if (slow_path == nullptr) {
4133 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4134 instruction->SetSlowPath(slow_path);
4135 codegen_->AddSlowPath(slow_path);
4136 if (successor != nullptr) {
4137 DCHECK(successor->IsLoopHeader());
4138 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4139 }
4140 } else {
4141 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4142 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004143
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004144 __ LoadFromOffset(
4145 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004146 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004147 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004148 __ Bind(slow_path->GetReturnLabel());
4149 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004150 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004151 __ b(slow_path->GetEntryLabel());
4152 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004153}
4154
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004155ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4156 return codegen_->GetAssembler();
4157}
4158
4159void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004160 DCHECK_LT(index, moves_.size());
4161 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004162 Location source = move->GetSource();
4163 Location destination = move->GetDestination();
4164
4165 if (source.IsRegister()) {
4166 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004167 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004168 } else {
4169 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004170 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004171 SP, destination.GetStackIndex());
4172 }
4173 } else if (source.IsStackSlot()) {
4174 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004175 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004176 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004177 } else if (destination.IsFpuRegister()) {
4178 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004179 } else {
4180 DCHECK(destination.IsStackSlot());
4181 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4182 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4183 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004184 } else if (source.IsFpuRegister()) {
4185 if (destination.IsFpuRegister()) {
4186 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004187 } else {
4188 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004189 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4190 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004191 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004192 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004193 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4194 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004195 } else if (destination.IsRegisterPair()) {
4196 DCHECK(ExpectedPairLayout(destination));
4197 __ LoadFromOffset(
4198 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4199 } else {
4200 DCHECK(destination.IsFpuRegisterPair()) << destination;
4201 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4202 SP,
4203 source.GetStackIndex());
4204 }
4205 } else if (source.IsRegisterPair()) {
4206 if (destination.IsRegisterPair()) {
4207 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4208 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4209 } else {
4210 DCHECK(destination.IsDoubleStackSlot()) << destination;
4211 DCHECK(ExpectedPairLayout(source));
4212 __ StoreToOffset(
4213 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4214 }
4215 } else if (source.IsFpuRegisterPair()) {
4216 if (destination.IsFpuRegisterPair()) {
4217 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4218 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4219 } else {
4220 DCHECK(destination.IsDoubleStackSlot()) << destination;
4221 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4222 SP,
4223 destination.GetStackIndex());
4224 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004225 } else {
4226 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004227 HConstant* constant = source.GetConstant();
4228 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4229 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004230 if (destination.IsRegister()) {
4231 __ LoadImmediate(destination.AsRegister<Register>(), value);
4232 } else {
4233 DCHECK(destination.IsStackSlot());
4234 __ LoadImmediate(IP, value);
4235 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4236 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004237 } else if (constant->IsLongConstant()) {
4238 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004239 if (destination.IsRegisterPair()) {
4240 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4241 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004242 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004243 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004244 __ LoadImmediate(IP, Low32Bits(value));
4245 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4246 __ LoadImmediate(IP, High32Bits(value));
4247 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4248 }
4249 } else if (constant->IsDoubleConstant()) {
4250 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004251 if (destination.IsFpuRegisterPair()) {
4252 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004253 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004254 DCHECK(destination.IsDoubleStackSlot()) << destination;
4255 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004256 __ LoadImmediate(IP, Low32Bits(int_value));
4257 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4258 __ LoadImmediate(IP, High32Bits(int_value));
4259 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4260 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004261 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004262 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004263 float value = constant->AsFloatConstant()->GetValue();
4264 if (destination.IsFpuRegister()) {
4265 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4266 } else {
4267 DCHECK(destination.IsStackSlot());
4268 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4269 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4270 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004271 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004272 }
4273}
4274
4275void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4276 __ Mov(IP, reg);
4277 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4278 __ StoreToOffset(kStoreWord, IP, SP, mem);
4279}
4280
4281void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4282 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4283 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4284 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4285 SP, mem1 + stack_offset);
4286 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4287 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4288 SP, mem2 + stack_offset);
4289 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4290}
4291
4292void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004293 DCHECK_LT(index, moves_.size());
4294 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004295 Location source = move->GetSource();
4296 Location destination = move->GetDestination();
4297
4298 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004299 DCHECK_NE(source.AsRegister<Register>(), IP);
4300 DCHECK_NE(destination.AsRegister<Register>(), IP);
4301 __ Mov(IP, source.AsRegister<Register>());
4302 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4303 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004304 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004305 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004306 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004307 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004308 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4309 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004310 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004311 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004312 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004313 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004314 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004315 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004316 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004317 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004318 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4319 destination.AsRegisterPairHigh<Register>(),
4320 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004321 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004322 Register low_reg = source.IsRegisterPair()
4323 ? source.AsRegisterPairLow<Register>()
4324 : destination.AsRegisterPairLow<Register>();
4325 int mem = source.IsRegisterPair()
4326 ? destination.GetStackIndex()
4327 : source.GetStackIndex();
4328 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004329 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004330 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004331 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004332 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004333 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4334 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004335 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004336 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004337 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004338 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4339 DRegister reg = source.IsFpuRegisterPair()
4340 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4341 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4342 int mem = source.IsFpuRegisterPair()
4343 ? destination.GetStackIndex()
4344 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004345 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004346 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004347 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004348 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4349 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4350 : destination.AsFpuRegister<SRegister>();
4351 int mem = source.IsFpuRegister()
4352 ? destination.GetStackIndex()
4353 : source.GetStackIndex();
4354
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004355 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004356 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004357 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004358 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004359 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4360 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004361 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004362 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004363 }
4364}
4365
4366void ParallelMoveResolverARM::SpillScratch(int reg) {
4367 __ Push(static_cast<Register>(reg));
4368}
4369
4370void ParallelMoveResolverARM::RestoreScratch(int reg) {
4371 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004372}
4373
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004374void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004375 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4376 ? LocationSummary::kCallOnSlowPath
4377 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004378 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004379 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004380 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004381 locations->SetOut(Location::RequiresRegister());
4382}
4383
4384void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004385 LocationSummary* locations = cls->GetLocations();
4386 Register out = locations->Out().AsRegister<Register>();
4387 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004388 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004389 DCHECK(!cls->CanCallRuntime());
4390 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004391 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004392 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004393 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004394 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004395 __ LoadFromOffset(kLoadWord,
4396 out,
4397 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004398 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004399 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004400 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004401
Andreas Gampe85b62f22015-09-09 13:15:38 -07004402 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004403 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4404 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004405 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004406 if (cls->MustGenerateClinitCheck()) {
4407 GenerateClassInitializationCheck(slow_path, out);
4408 } else {
4409 __ Bind(slow_path->GetExitLabel());
4410 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004411 }
4412}
4413
4414void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4415 LocationSummary* locations =
4416 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4417 locations->SetInAt(0, Location::RequiresRegister());
4418 if (check->HasUses()) {
4419 locations->SetOut(Location::SameAsFirstInput());
4420 }
4421}
4422
4423void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004424 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004425 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004426 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004427 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004428 GenerateClassInitializationCheck(slow_path,
4429 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004430}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004431
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004432void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004433 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004434 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4435 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4436 __ b(slow_path->GetEntryLabel(), LT);
4437 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4438 // properly. Therefore, we do a memory fence.
4439 __ dmb(ISH);
4440 __ Bind(slow_path->GetExitLabel());
4441}
4442
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004443void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4444 LocationSummary* locations =
4445 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004446 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004447 locations->SetOut(Location::RequiresRegister());
4448}
4449
4450void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004451 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004452 codegen_->AddSlowPath(slow_path);
4453
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004454 LocationSummary* locations = load->GetLocations();
4455 Register out = locations->Out().AsRegister<Register>();
4456 Register current_method = locations->InAt(0).AsRegister<Register>();
4457 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004458 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004459 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004460 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004461 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004462 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004463 __ Bind(slow_path->GetExitLabel());
4464}
4465
David Brazdilcb1c0552015-08-04 16:22:25 +01004466static int32_t GetExceptionTlsOffset() {
4467 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4468}
4469
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004470void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4471 LocationSummary* locations =
4472 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4473 locations->SetOut(Location::RequiresRegister());
4474}
4475
4476void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004477 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004478 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4479}
4480
4481void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4482 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4483}
4484
4485void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004486 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004487 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004488}
4489
4490void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4491 LocationSummary* locations =
4492 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4493 InvokeRuntimeCallingConvention calling_convention;
4494 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4495}
4496
4497void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4498 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004499 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004500}
4501
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004502void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004503 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4504 switch (instruction->GetTypeCheckKind()) {
4505 case TypeCheckKind::kExactCheck:
4506 case TypeCheckKind::kAbstractClassCheck:
4507 case TypeCheckKind::kClassHierarchyCheck:
4508 case TypeCheckKind::kArrayObjectCheck:
4509 call_kind = LocationSummary::kNoCall;
4510 break;
4511 case TypeCheckKind::kInterfaceCheck:
4512 call_kind = LocationSummary::kCall;
4513 break;
4514 case TypeCheckKind::kArrayCheck:
4515 call_kind = LocationSummary::kCallOnSlowPath;
4516 break;
4517 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004518 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004519 if (call_kind != LocationSummary::kCall) {
4520 locations->SetInAt(0, Location::RequiresRegister());
4521 locations->SetInAt(1, Location::RequiresRegister());
4522 // The out register is used as a temporary, so it overlaps with the inputs.
4523 // Note that TypeCheckSlowPathARM uses this register too.
4524 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4525 } else {
4526 InvokeRuntimeCallingConvention calling_convention;
4527 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4528 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4529 locations->SetOut(Location::RegisterLocation(R0));
4530 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004531}
4532
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004533void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004534 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004535 Register obj = locations->InAt(0).AsRegister<Register>();
4536 Register cls = locations->InAt(1).AsRegister<Register>();
4537 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004538 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004539 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4540 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4541 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004542 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004543 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004544
4545 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004546 // avoid null check if we know obj is not null.
4547 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004548 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004549 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004550
4551 // In case of an interface check, we put the object class into the object register.
4552 // This is safe, as the register is caller-save, and the object must be in another
4553 // register if it survives the runtime call.
4554 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
4555 ? obj
4556 : out;
4557 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4558 __ MaybeUnpoisonHeapReference(target);
4559
4560 switch (instruction->GetTypeCheckKind()) {
4561 case TypeCheckKind::kExactCheck: {
4562 __ cmp(out, ShifterOperand(cls));
4563 // Classes must be equal for the instanceof to succeed.
4564 __ b(&zero, NE);
4565 __ LoadImmediate(out, 1);
4566 __ b(&done);
4567 break;
4568 }
4569 case TypeCheckKind::kAbstractClassCheck: {
4570 // If the class is abstract, we eagerly fetch the super class of the
4571 // object to avoid doing a comparison we know will fail.
4572 Label loop;
4573 __ Bind(&loop);
4574 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4575 __ MaybeUnpoisonHeapReference(out);
4576 // If `out` is null, we use it for the result, and jump to `done`.
4577 __ CompareAndBranchIfZero(out, &done);
4578 __ cmp(out, ShifterOperand(cls));
4579 __ b(&loop, NE);
4580 __ LoadImmediate(out, 1);
4581 if (zero.IsLinked()) {
4582 __ b(&done);
4583 }
4584 break;
4585 }
4586 case TypeCheckKind::kClassHierarchyCheck: {
4587 // Walk over the class hierarchy to find a match.
4588 Label loop, success;
4589 __ Bind(&loop);
4590 __ cmp(out, ShifterOperand(cls));
4591 __ b(&success, EQ);
4592 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4593 __ MaybeUnpoisonHeapReference(out);
4594 __ CompareAndBranchIfNonZero(out, &loop);
4595 // If `out` is null, we use it for the result, and jump to `done`.
4596 __ b(&done);
4597 __ Bind(&success);
4598 __ LoadImmediate(out, 1);
4599 if (zero.IsLinked()) {
4600 __ b(&done);
4601 }
4602 break;
4603 }
4604 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004605 // Do an exact check.
4606 Label exact_check;
4607 __ cmp(out, ShifterOperand(cls));
4608 __ b(&exact_check, EQ);
4609 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004610 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4611 __ MaybeUnpoisonHeapReference(out);
4612 // If `out` is null, we use it for the result, and jump to `done`.
4613 __ CompareAndBranchIfZero(out, &done);
4614 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4615 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4616 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004617 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004618 __ LoadImmediate(out, 1);
4619 __ b(&done);
4620 break;
4621 }
4622 case TypeCheckKind::kArrayCheck: {
4623 __ cmp(out, ShifterOperand(cls));
4624 DCHECK(locations->OnlyCallsOnSlowPath());
4625 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4626 instruction, /* is_fatal */ false);
4627 codegen_->AddSlowPath(slow_path);
4628 __ b(slow_path->GetEntryLabel(), NE);
4629 __ LoadImmediate(out, 1);
4630 if (zero.IsLinked()) {
4631 __ b(&done);
4632 }
4633 break;
4634 }
4635
4636 case TypeCheckKind::kInterfaceCheck:
4637 default: {
4638 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4639 instruction,
4640 instruction->GetDexPc(),
4641 nullptr);
4642 if (zero.IsLinked()) {
4643 __ b(&done);
4644 }
4645 break;
4646 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004647 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004648
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004649 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004650 __ Bind(&zero);
4651 __ LoadImmediate(out, 0);
4652 }
4653
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004654 if (done.IsLinked()) {
4655 __ Bind(&done);
4656 }
4657
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004658 if (slow_path != nullptr) {
4659 __ Bind(slow_path->GetExitLabel());
4660 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004661}
4662
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004663void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004664 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4665 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4666
4667 switch (instruction->GetTypeCheckKind()) {
4668 case TypeCheckKind::kExactCheck:
4669 case TypeCheckKind::kAbstractClassCheck:
4670 case TypeCheckKind::kClassHierarchyCheck:
4671 case TypeCheckKind::kArrayObjectCheck:
4672 call_kind = throws_into_catch
4673 ? LocationSummary::kCallOnSlowPath
4674 : LocationSummary::kNoCall;
4675 break;
4676 case TypeCheckKind::kInterfaceCheck:
4677 call_kind = LocationSummary::kCall;
4678 break;
4679 case TypeCheckKind::kArrayCheck:
4680 call_kind = LocationSummary::kCallOnSlowPath;
4681 break;
4682 }
4683
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004684 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004685 instruction, call_kind);
4686 if (call_kind != LocationSummary::kCall) {
4687 locations->SetInAt(0, Location::RequiresRegister());
4688 locations->SetInAt(1, Location::RequiresRegister());
4689 // Note that TypeCheckSlowPathARM uses this register too.
4690 locations->AddTemp(Location::RequiresRegister());
4691 } else {
4692 InvokeRuntimeCallingConvention calling_convention;
4693 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4694 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4695 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004696}
4697
4698void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4699 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004700 Register obj = locations->InAt(0).AsRegister<Register>();
4701 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004702 Register temp = locations->WillCall()
4703 ? Register(kNoRegister)
4704 : locations->GetTemp(0).AsRegister<Register>();
4705
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004706 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004707 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4708 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4709 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4710 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004711
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004712 if (!locations->WillCall()) {
4713 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4714 instruction, !locations->CanCall());
4715 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004716 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004717
4718 Label done;
4719 // Avoid null check if we know obj is not null.
4720 if (instruction->MustDoNullCheck()) {
4721 __ CompareAndBranchIfZero(obj, &done);
4722 }
4723
4724 if (locations->WillCall()) {
4725 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4726 __ MaybeUnpoisonHeapReference(obj);
4727 } else {
4728 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4729 __ MaybeUnpoisonHeapReference(temp);
4730 }
4731
4732 switch (instruction->GetTypeCheckKind()) {
4733 case TypeCheckKind::kExactCheck:
4734 case TypeCheckKind::kArrayCheck: {
4735 __ cmp(temp, ShifterOperand(cls));
4736 // Jump to slow path for throwing the exception or doing a
4737 // more involved array check.
4738 __ b(slow_path->GetEntryLabel(), NE);
4739 break;
4740 }
4741 case TypeCheckKind::kAbstractClassCheck: {
4742 // If the class is abstract, we eagerly fetch the super class of the
4743 // object to avoid doing a comparison we know will fail.
4744 Label loop;
4745 __ Bind(&loop);
4746 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4747 __ MaybeUnpoisonHeapReference(temp);
4748 // Jump to the slow path to throw the exception.
4749 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4750 __ cmp(temp, ShifterOperand(cls));
4751 __ b(&loop, NE);
4752 break;
4753 }
4754 case TypeCheckKind::kClassHierarchyCheck: {
4755 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004756 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004757 __ Bind(&loop);
4758 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004759 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004760 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4761 __ MaybeUnpoisonHeapReference(temp);
4762 __ CompareAndBranchIfNonZero(temp, &loop);
4763 // Jump to the slow path to throw the exception.
4764 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004765 break;
4766 }
4767 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004768 // Do an exact check.
4769 __ cmp(temp, ShifterOperand(cls));
4770 __ b(&done, EQ);
4771 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004772 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
4773 __ MaybeUnpoisonHeapReference(temp);
4774 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4775 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
4776 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4777 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
4778 break;
4779 }
4780 case TypeCheckKind::kInterfaceCheck:
4781 default:
4782 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
4783 instruction,
4784 instruction->GetDexPc(),
4785 nullptr);
4786 break;
4787 }
4788 __ Bind(&done);
4789
4790 if (slow_path != nullptr) {
4791 __ Bind(slow_path->GetExitLabel());
4792 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004793}
4794
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004795void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4796 LocationSummary* locations =
4797 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4798 InvokeRuntimeCallingConvention calling_convention;
4799 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4800}
4801
4802void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4803 codegen_->InvokeRuntime(instruction->IsEnter()
4804 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4805 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004806 instruction->GetDexPc(),
4807 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004808}
4809
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004810void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4811void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4812void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4813
4814void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4815 LocationSummary* locations =
4816 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4817 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4818 || instruction->GetResultType() == Primitive::kPrimLong);
4819 locations->SetInAt(0, Location::RequiresRegister());
4820 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004821 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004822}
4823
4824void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4825 HandleBitwiseOperation(instruction);
4826}
4827
4828void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4829 HandleBitwiseOperation(instruction);
4830}
4831
4832void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4833 HandleBitwiseOperation(instruction);
4834}
4835
4836void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4837 LocationSummary* locations = instruction->GetLocations();
4838
4839 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004840 Register first = locations->InAt(0).AsRegister<Register>();
4841 Register second = locations->InAt(1).AsRegister<Register>();
4842 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004843 if (instruction->IsAnd()) {
4844 __ and_(out, first, ShifterOperand(second));
4845 } else if (instruction->IsOr()) {
4846 __ orr(out, first, ShifterOperand(second));
4847 } else {
4848 DCHECK(instruction->IsXor());
4849 __ eor(out, first, ShifterOperand(second));
4850 }
4851 } else {
4852 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4853 Location first = locations->InAt(0);
4854 Location second = locations->InAt(1);
4855 Location out = locations->Out();
4856 if (instruction->IsAnd()) {
4857 __ and_(out.AsRegisterPairLow<Register>(),
4858 first.AsRegisterPairLow<Register>(),
4859 ShifterOperand(second.AsRegisterPairLow<Register>()));
4860 __ and_(out.AsRegisterPairHigh<Register>(),
4861 first.AsRegisterPairHigh<Register>(),
4862 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4863 } else if (instruction->IsOr()) {
4864 __ orr(out.AsRegisterPairLow<Register>(),
4865 first.AsRegisterPairLow<Register>(),
4866 ShifterOperand(second.AsRegisterPairLow<Register>()));
4867 __ orr(out.AsRegisterPairHigh<Register>(),
4868 first.AsRegisterPairHigh<Register>(),
4869 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4870 } else {
4871 DCHECK(instruction->IsXor());
4872 __ eor(out.AsRegisterPairLow<Register>(),
4873 first.AsRegisterPairLow<Register>(),
4874 ShifterOperand(second.AsRegisterPairLow<Register>()));
4875 __ eor(out.AsRegisterPairHigh<Register>(),
4876 first.AsRegisterPairHigh<Register>(),
4877 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4878 }
4879 }
4880}
4881
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004882void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004883 // For better instruction scheduling we load the direct code pointer before the method pointer.
4884 bool direct_code_loaded = false;
4885 switch (invoke->GetCodePtrLocation()) {
4886 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4887 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4888 break;
4889 }
4890 // Calls across dex files are more likely to exceed the available BL range,
4891 // so use absolute patch by falling through to kDirectCodeFixup.
4892 FALLTHROUGH_INTENDED;
4893 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4894 // LR = code address from literal pool with link-time patch.
4895 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4896 direct_code_loaded = true;
4897 break;
4898 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4899 // LR = invoke->GetDirectCodePtr();
4900 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4901 direct_code_loaded = true;
4902 break;
4903 default:
4904 break;
4905 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004906
Vladimir Marko58155012015-08-19 12:49:41 +00004907 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4908 switch (invoke->GetMethodLoadKind()) {
4909 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
4910 // temp = thread->string_init_entrypoint
4911 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
4912 break;
4913 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4914 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4915 break;
4916 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4917 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4918 break;
4919 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4920 __ LoadLiteral(temp.AsRegister<Register>(),
4921 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4922 break;
4923 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
4924 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
4925 FALLTHROUGH_INTENDED;
4926 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4927 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4928 Register method_reg;
4929 Register reg = temp.AsRegister<Register>();
4930 if (current_method.IsRegister()) {
4931 method_reg = current_method.AsRegister<Register>();
4932 } else {
4933 DCHECK(invoke->GetLocations()->Intrinsified());
4934 DCHECK(!current_method.IsValid());
4935 method_reg = reg;
4936 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
4937 }
4938 // temp = current_method->dex_cache_resolved_methods_;
4939 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01004940 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
4941 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00004942 // temp = temp[index_in_cache]
4943 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
4944 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
4945 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01004946 }
Vladimir Marko58155012015-08-19 12:49:41 +00004947 }
4948
4949 switch (invoke->GetCodePtrLocation()) {
4950 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
4951 __ bl(GetFrameEntryLabel());
4952 break;
4953 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4954 if (!direct_code_loaded) {
4955 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
4956 __ Bind(&relative_call_patches_.back().label);
4957 Label label;
4958 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
4959 __ Bind(&label);
4960 break;
4961 }
4962 // If we loaded the direct code above, fall through.
4963 FALLTHROUGH_INTENDED;
4964 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4965 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4966 // LR prepared above for better instruction scheduling.
4967 DCHECK(direct_code_loaded);
4968 // LR()
4969 __ blx(LR);
4970 break;
4971 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4972 // LR = callee_method->entry_point_from_quick_compiled_code_
4973 __ LoadFromOffset(
4974 kLoadWord, LR, callee_method.AsRegister<Register>(),
4975 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
4976 // LR()
4977 __ blx(LR);
4978 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004979 }
4980
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004981 DCHECK(!IsLeafMethod());
4982}
4983
Andreas Gampebfb5ba92015-09-01 15:45:02 +00004984void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
4985 Register temp = temp_location.AsRegister<Register>();
4986 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
4987 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
4988 LocationSummary* locations = invoke->GetLocations();
4989 Location receiver = locations->InAt(0);
4990 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4991 // temp = object->GetClass();
4992 DCHECK(receiver.IsRegister());
4993 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
4994 MaybeRecordImplicitNullCheck(invoke);
4995 __ MaybeUnpoisonHeapReference(temp);
4996 // temp = temp->GetMethodAt(method_offset);
4997 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4998 kArmWordSize).Int32Value();
4999 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5000 // LR = temp->GetEntryPoint();
5001 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
5002 // LR();
5003 __ blx(LR);
5004}
5005
Vladimir Marko58155012015-08-19 12:49:41 +00005006void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
5007 DCHECK(linker_patches->empty());
5008 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
5009 linker_patches->reserve(size);
5010 for (const auto& entry : method_patches_) {
5011 const MethodReference& target_method = entry.first;
5012 Literal* literal = entry.second;
5013 DCHECK(literal->GetLabel()->IsBound());
5014 uint32_t literal_offset = literal->GetLabel()->Position();
5015 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
5016 target_method.dex_file,
5017 target_method.dex_method_index));
5018 }
5019 for (const auto& entry : call_patches_) {
5020 const MethodReference& target_method = entry.first;
5021 Literal* literal = entry.second;
5022 DCHECK(literal->GetLabel()->IsBound());
5023 uint32_t literal_offset = literal->GetLabel()->Position();
5024 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
5025 target_method.dex_file,
5026 target_method.dex_method_index));
5027 }
5028 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
5029 uint32_t literal_offset = info.label.Position();
5030 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
5031 info.target_method.dex_file,
5032 info.target_method.dex_method_index));
5033 }
5034}
5035
5036Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
5037 MethodToLiteralMap* map) {
5038 // Look up the literal for target_method.
5039 auto lb = map->lower_bound(target_method);
5040 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
5041 return lb->second;
5042 }
5043 // We don't have a literal for this method yet, insert a new one.
5044 Literal* literal = __ NewLiteral<uint32_t>(0u);
5045 map->PutBefore(lb, target_method, literal);
5046 return literal;
5047}
5048
5049Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
5050 return DeduplicateMethodLiteral(target_method, &method_patches_);
5051}
5052
5053Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
5054 return DeduplicateMethodLiteral(target_method, &call_patches_);
5055}
5056
Calin Juravleb1498f62015-02-16 13:13:29 +00005057void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
5058 // Nothing to do, this should be removed during prepare for register allocator.
5059 UNUSED(instruction);
5060 LOG(FATAL) << "Unreachable";
5061}
5062
5063void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
5064 // Nothing to do, this should be removed during prepare for register allocator.
5065 UNUSED(instruction);
5066 LOG(FATAL) << "Unreachable";
5067}
5068
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005069void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
5070 DCHECK(codegen_->IsBaseline());
5071 LocationSummary* locations =
5072 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5073 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5074}
5075
5076void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5077 DCHECK(codegen_->IsBaseline());
5078 // Will be generated at use site.
5079}
5080
Mark Mendellfe57faa2015-09-18 09:26:15 -04005081// Simple implementation of packed switch - generate cascaded compare/jumps.
5082void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5083 LocationSummary* locations =
5084 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5085 locations->SetInAt(0, Location::RequiresRegister());
5086}
5087
5088void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5089 int32_t lower_bound = switch_instr->GetStartValue();
5090 int32_t num_entries = switch_instr->GetNumEntries();
5091 LocationSummary* locations = switch_instr->GetLocations();
5092 Register value_reg = locations->InAt(0).AsRegister<Register>();
5093 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5094
5095 // Create a series of compare/jumps.
5096 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5097 for (int32_t i = 0; i < num_entries; i++) {
5098 GenerateCompareWithImmediate(value_reg, lower_bound + i);
5099 __ b(codegen_->GetLabelOf(successors.at(i)), EQ);
5100 }
5101
5102 // And the default for any other value.
5103 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5104 __ b(codegen_->GetLabelOf(default_block));
5105 }
5106}
5107
Andreas Gampe85b62f22015-09-09 13:15:38 -07005108void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5109 if (!trg.IsValid()) {
5110 DCHECK(type == Primitive::kPrimVoid);
5111 return;
5112 }
5113
5114 DCHECK_NE(type, Primitive::kPrimVoid);
5115
5116 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
5117 if (return_loc.Equals(trg)) {
5118 return;
5119 }
5120
5121 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5122 // with the last branch.
5123 if (type == Primitive::kPrimLong) {
5124 HParallelMove parallel_move(GetGraph()->GetArena());
5125 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5126 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5127 GetMoveResolver()->EmitNativeCode(&parallel_move);
5128 } else if (type == Primitive::kPrimDouble) {
5129 HParallelMove parallel_move(GetGraph()->GetArena());
5130 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5131 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5132 GetMoveResolver()->EmitNativeCode(&parallel_move);
5133 } else {
5134 // Let the parallel move resolver take care of all of this.
5135 HParallelMove parallel_move(GetGraph()->GetArena());
5136 parallel_move.AddMove(return_loc, trg, type, nullptr);
5137 GetMoveResolver()->EmitNativeCode(&parallel_move);
5138 }
5139}
5140
Roland Levillain4d027112015-07-01 15:41:14 +01005141#undef __
5142#undef QUICK_ENTRY_POINT
5143
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005144} // namespace arm
5145} // namespace art